bzoj4199 [Noi2015]品酒大会 后缀数组+并查集

来源:互联网 发布:淘宝实体店加盟条件 编辑:程序博客网 时间:2024/05/22 17:20

题目大意:
定义字符串s的两个子串为r相似的当起始位置不同的两个长度为r子串完全相同。
第一问: 对于每一个r,求出r相似的子串有多少对,0<=r

#include <cstdio>#include <algorithm>#include <iostream>#define N 320000using namespace std;typedef long long LL;const LL INF=0x3f3f3f3f;inline int Min(int x,int y) { return x<y?x:y; }inline int Max(int x,int y) { return x>y?x:y; }inline LL Max(LL x,LL y) { return x>y?x:y; }int n,tot;LL cnt[N],tcnt,ans[N],tmax=-INF*INF;int f[N],mx[N],cm[N],sz[N],a[N],mi[N],ci[N];int sa[N],rnk[N],h[N],tmp[N],sum[N],X[N],Y[N];char s[N];int findie(int c){    if(f[c]!=c) f[c]=findie(f[c]);    return f[c];}void Union(int x,int y){    int t1=findie(x);    int t2=findie(y);    if(sz[t2]>sz[t1]) swap(t1,t2);    tcnt+=1ll*sz[t1]*sz[t2];    f[t2]=t1; sz[t1]+=sz[t2];    if(mx[t2]>mx[t1]) cm[t1]=mx[t1],mx[t1]=mx[t2];    else if(mx[t2]>cm[t1]) cm[t1]=mx[t2];    if(cm[t2]>cm[t1]) cm[t1]=cm[t2];    if(mi[t2]<mi[t1]) ci[t1]=mi[t1],mi[t1]=mi[t2];    else if(mi[t2]<ci[t1]) ci[t1]=mi[t2];    if(ci[t2]<ci[t1]) ci[t1]=ci[t2];    tmax=Max(tmax,1ll*mx[t1]*cm[t1]);    tmax=Max(tmax,1ll*mi[t1]*ci[t1]);    return;}void get_rank(){    for(int i=0;i<=127;i++) sum[i]=0;    for(int i=1;i<=tot;i++) sum[s[i]]++;    for(int i=1;i<=127;i++) sum[i]+=sum[i-1];    for(int i=tot;i>=1;i--) tmp[sum[s[i]]--]=i;    for(int i=1,t=0;i<=tot;i++)    {        if(i==1 || s[tmp[i]]!=s[tmp[i-1]]) t++;        rnk[tmp[i]]=t;    }    return;}void digit_sort(int key[],int order[]){    for(int i=0;i<=tot;i++) sum[i]=0;    for(int i=1;i<=tot;i++) sum[key[i]]++;    for(int i=1;i<=tot;i++) sum[i]+=sum[i-1];    for(int i=tot;i>=1;i--) tmp[sum[key[order[i]]]--]=order[i];    for(int i=1;i<=tot;i++) order[i]=tmp[i];}void get_height(){    int j,k;    for(int i=1;i<=tot;i++)    {        if(rnk[i]==1) continue;        k=Max(h[rnk[i-1]]-1,0);        j=sa[rnk[i]-1];        while(s[i+k]==s[j+k]) k++;        h[rnk[i]]=k;    }}void Suffix_Array(){    get_rank();    for(int j=1;j<=tot;j<<=1)    {        for(int i=1;i<=tot;i++)        {            sa[i]=i;            X[i]=rnk[i];            Y[i]=i+j<=tot?rnk[i+j]:0;        }        digit_sort(Y,sa);        digit_sort(X,sa);        for(int i=1,t=0;i<=tot;i++)        {            if(i==1 || X[sa[i]]!=X[sa[i-1]] || Y[sa[i]]!=Y[sa[i-1]]) t++;            rnk[sa[i]]=t;        }    }    get_height();}bool cmp(int x,int y) { return h[x]>h[y]; }int main(){    scanf("%d",&n); tot=n;    scanf("%s",s+1);    for(int i=1;i<=n;i++) scanf("%d",&a[i]);    Suffix_Array();    for(int i=1;i<=n;i++)    {        f[i]=i; sz[i]=1;        mx[i]=a[sa[i]]; mi[i]=a[sa[i]];        cm[i]=-INF; ci[i]=INF;        tmp[i]=i;    }    sort(tmp+2,tmp+n+1,cmp);    int now=2;    for(int i=n-1;i>=0;i--)    {        while(now<=n && h[tmp[now]]==i)        {            Union(tmp[now],tmp[now]-1);            now++;        }        cnt[i]=tcnt;        ans[i]=tcnt?tmax:0;    }    for(int i=0;i<n;i++)        printf("%lld %lld\n",cnt[i],ans[i]);    return 0;}