码迷,mamicode.com
首页 > 编程语言 > 详细

zoj千题计划312:bzoj3879: SvT(后缀数组+st表+单调栈)

时间:2018-05-01 23:49:07      阅读:247      评论:0      收藏:0      [点我收藏+]

标签:取出   min   tps   AC   bsp   line   http   etc   后缀   

https://www.lydsy.com/JudgeOnline/problem.php?id=3879

 

把所有的后缀取出,按rank排序

求出相邻两个后缀的lcp

每个后缀对答案的贡献就是 与在它之前的后缀的lcp之和

维护一个单调递增的栈,记录栈中元素的lcp之和 即可

 

#include<cstdio>
#include<iostream>
#include<algorithm>

using namespace std;

#define N 500001
#define M 3000001

int n,m,mm;
char s[N];
int a[N];

int b[M],r[N];

int v[N];
int p,q=1,k;
int sa[2][N],rk[2][N];

int height[N],h[N];
int st[N][16];

int Log[N];

int ST[N],top;
int num[N],val[N];

void read(int &x)
{
    x=0; char c=getchar();
    while(!isdigit(c)) c=getchar();
    while(isdigit(c)) { x=x*10+c-0; c=getchar(); }
}

void mul(int *sa,int *rk,int *SA,int *RK)
{
    for(int i=1;i<=n;++i) v[rk[sa[i]]]=i;
    for(int i=n;i;--i) if(sa[i]>k) SA[v[rk[sa[i]-k]]--]=sa[i]-k;
    for(int i=n-k+1;i<=n;++i) SA[v[rk[i]]--]=i;
    for(int i=1;i<=n;++i) RK[SA[i]]=RK[SA[i-1]]+(rk[SA[i]]!=rk[SA[i-1]] || rk[SA[i]+k]!=rk[SA[i-1]+k]);
}

void presa()
{
    for(int i=1;i<=n;++i) v[a[i]]++;
    for(int i=1;i<=26;++i) v[i]+=v[i-1];
    for(int i=1;i<=n;++i) sa[p][v[a[i]]--]=i;
    for(int i=1;i<=n;++i) rk[p][sa[p][i]]=rk[p][sa[p][i-1]]+(a[sa[p][i]]!=a[sa[p][i-1]]);
    for(k=1;k<n;k<<=1,swap(p,q)) mul(sa[p],rk[p],sa[q],rk[q]);
}

void get_height()
{
    int k=0,j;
    for(int i=1;i<=n;++i)
    {
        j=sa[p][rk[p][i]-1];
        while(a[i+k]==a[j+k]) k++;
        height[rk[p][i]]=k;
        if(k) k--;
    }
}

void prest()
{
    for(int i=2;i<=n;++i) st[i][0]=height[i];
    for(int i=1,k=2;i<=15;++i,k<<=1)
        for(int j=2;j+k-1<=n;++j) 
            st[j][i]=min(st[j][i-1],st[j+k/2][i-1]);
}

int get(int i,int j)
{
    i++;
    int l=Log[j-i+1];
    return min(st[i][l],st[j-(1<<l)+1][l]);
}

void solve()
{
    for(int i=1;i<=mm;++i) r[i]=rk[p][b[i]];
    sort(r+1,r+mm+1);
    for(int i=2;i<=mm;++i) h[i]=get(r[i-1],r[i]);
    top=0;
    int tmp_num;
    long long now=0,ans=0;
    for(int i=2;i<=mm;++i)
    {
        tmp_num=0;
        while(top && h[i]<=h[ST[top]]) 
        {
            now-=1LL*num[top]*val[top];
            tmp_num+=num[top--];
        }
        tmp_num++;
        ST[++top]=i;
        num[top]=tmp_num;
        val[top]=h[i];
        now+=1LL*tmp_num*h[i];
        ans+=now;
    }
    cout<<ans<<\n;
}

int main()
{
    int T;
    read(n); read(T);
    for(int i=2;i<=n;++i) Log[i]=Log[i>>1]+1;
    scanf("%s",s+1);
    for(int i=1;i<=n;++i) a[i]=s[i]-a+1;
    presa();
    get_height();
    prest();
    while(T--)
    {
        read(m);
        for(int i=1;i<=m;++i) read(b[i]);
        sort(b+1,b+m+1);
        mm=unique(b+1,b+m+1)-b-1;
        solve();
    }
}

 

zoj千题计划312:bzoj3879: SvT(后缀数组+st表+单调栈)

标签:取出   min   tps   AC   bsp   line   http   etc   后缀   

原文地址:https://www.cnblogs.com/TheRoadToTheGold/p/8977430.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!