【BZOJ4199】【NOI2015】—品酒大会(后缀数组)

传送门

很显然kk相似就是所有klcpk \le lcp的后缀

排序后不断加入,用个并查集维护一下合并两段的信息,大小,最大值,最小值就可以了

据说某些题解过不了样例?

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
inline int read(){
    char ch=getchar();
    int res=0,f=1;
    while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();}
    while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=getchar();
    return res*f;
}
const int N=300005;
int n,fa[N],mx[N],mn[N],siz[N],pos[N];
ll ans[N],ans1[N],ans2[N];
char s[N];
struct Sa{
    int m,a[N],rk[N],sa[N],sa2[N],cnt[N],ht[N];
    inline void bucket_sort(){
        for(int i=1;i<=m;i++)cnt[i]=0;
        for(int i=1;i<=n;i++)++cnt[rk[sa2[i]]];
        for(int i=1;i<=m;i++)cnt[i]+=cnt[i-1];
        for(int i=n;i>=1;i--)sa[cnt[rk[sa2[i]]]--]=sa2[i];
    }
    inline void build(){
        m=30;
        for(int i=1;i<=n;i++)rk[i]=a[i],sa2[i]=i;
        bucket_sort();
        for(int i=1,pos=0;i<=n&&pos<n;i<<=1){
            pos=0;
            for(int j=n-i+1;j<=n;j++)sa2[++pos]=j;
            for(int j=1;j<=n;j++)if(sa[j]>i)sa2[++pos]=sa[j]-i;
            bucket_sort();
            swap(rk,sa2);
            rk[sa[1]]=1,pos=1;
            for(int j=2;j<=n;j++)
                rk[sa[j]]=((sa2[sa[j]]==sa2[sa[j-1]])&&(sa2[sa[j]+i]==sa2[sa[j-1]+i])?pos:++pos);
            m=pos;
        }
        for(int i=1;i<=n;i++)rk[sa[i]]=i;
        for(int i=1,k=0,j;i<=n;ht[rk[i++]]=k){
            for(k?k--:0,j=sa[rk[i]-1];a[i+k]==a[j+k];k++);
        }
    }
}T;
inline bool comp(int a,int b){
    return T.ht[a]>T.ht[b];
}
inline int find(int x){
    return fa[x]==x?x:fa[x]=find(fa[x]);
}
inline void chemx(ll &a,ll b){
    a=a>b?a:b;
}
inline void merge(int f1,int f2,int k){
    f1=find(f1),f2=find(f2);
    fa[f2]=f1;
    ans1[k]+=1ll*siz[f1]*siz[f2];
    siz[f1]+=siz[f2];
    chemx(ans[f1],ans[f2]);
    chemx(ans[f1],1ll*mx[f1]*mx[f2]);
    chemx(ans[f1],1ll*mn[f1]*mn[f2]);
    mn[f1]=min(mn[f1],mn[f2]);
    mx[f1]=max(mx[f1],mx[f2]);
    ans2[k]=max(ans2[k],ans[f1]);
}
int main(){
    n=read();
    scanf("%s",s+1);
    for(int i=1;i<=n;i++)T.a[i]=s[i]-'a'+1;T.build();
    for(int i=1;i<=n;i++)siz[i]=1,fa[i]=i,mx[i]=mn[i]=read(),pos[i]=i;
    memset(ans2,128,sizeof(ans2));
    memset(ans,128,sizeof(ans));
    sort(pos+2,pos+n+1,comp);
    for(int i=2;i<=n;i++)
        merge(T.sa[pos[i]],T.sa[pos[i]-1],T.ht[pos[i]]);
    for(int i=n;~i;i--)ans1[i]+=ans1[i+1],ans2[i]=max(ans2[i],ans2[i+1]);
    for(int i=0;i<n;i++)cout<<ans1[i]<<" "<<(ans1[i]?ans2[i]:0)<<'\n';
}
posted @ 2019-03-25 19:01  Stargazer_cykoi  阅读(120)  评论(0编辑  收藏  举报