后缀数组+并查集
先求出height数组 然后排序
并查集维护 size max min
从大到小枚举height
若当前以x开头的后缀和以y开头的后缀的lcp为k
p为x的并查集的根,q为y的并查集的根
则k相似的的个数 加上size[p]*size[q]
最大值更新 max{mx[p]*mx[q],mn[p]*mn[q],mx[p]*mn[q],mn[p]*mx[q]}
#include<cstdio> #include<cstdlib> #include<cmath> #include<cstring> #include<queue> #include<vector> #include<set> #include<map> #include<iostream> #include<algorithm> #define T 311111 #define ll long long #define MN 1000000000000000000ll using namespace std; int sc() { int i=0,f=1;char c=getchar(); while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9')i=i*10+c-'0',c=getchar(); return i*f; } struct E{int v,pos;}a[T]; char s[T]; int t1[T],t2[T],cc[T],rank[T],sa[T],height[T]; int v[T],n,size[T],fa[T],len; long long ans1[T],ans2[T],mx[T],mn[T],ans[T]; bool cmp1(E a,E b){return a.v>b.v;} bool cmp(int *y,int a,int b,int k) { int a1=y[a],b1=y[b]; int a2=a+k>=len?-1:y[a+k]; int b2=b+k>=len?-1:y[b+k]; return a1==b1&&a2==b2; } void make_sa() { int *x=t1,*y=t2,m=333; for(int i=0;i<m;i++)cc[i]=0; for(int i=0;i<len;i++)++cc[x[i]=s[i]]; for(int i=1;i<m;i++)cc[i]+=cc[i-1]; for(int i=len-1;~i;i--)sa[--cc[x[i]]]=i; for(int k=1;k<=len;k<<=1) { int p=0; for(int i=len-k;i<len;i++)y[p++]=i; for(int i=0;i<len;i++)if(sa[i]-k>=0)y[p++]=sa[i]-k; for(int i=0;i<m;i++)cc[i]=0; for(int i=0;i<len;i++)++cc[x[y[i]]]; for(int i=1;i<m;i++)cc[i]+=cc[i-1]; for(int i=len-1;~i;i--)sa[--cc[x[y[i]]]]=y[i]; swap(x,y),m=1,x[sa[0]]=0; for(int i=1;i<len;i++)x[sa[i]]=cmp(y,sa[i],sa[i-1],k)?m-1:m++; if(m>=len)return; } } void make_height() { int k=0; for(int i=0;i<len;i++)rank[sa[i]]=i; for(int i=0;i<len;i++) { if(!rank[i])continue; int j=sa[rank[i]-1]; if(k)k--; while(s[i+k]==s[j+k])k++; height[rank[i]]=k; } } int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);} void Union(int x,int y) { fa[x]=y; size[y]+=size[x]; ans[y]=max(max(ans[x],ans[y]),max(mx[x]*mx[y],mn[x]*mn[y])); ans[y]=max(ans[y],max(mx[y]*mn[x],mx[x]*mn[y])); mx[y]=max(mx[y],mx[x]); mn[y]=min(mn[y],mn[x]); } int main() { n=sc();scanf("%s",s); len=n; for(int i=0;i<n;i++)v[i]=sc(); make_sa(),make_height(); for(int i=1;i<len;i++)a[i].v=height[i],a[i].pos=i; sort(a+1,a+len,cmp1); for(int i=0;i<len;i++)fa[i]=i,size[i]=1,mx[i]=v[i],mn[i]=v[i],ans[i]=-MN; for(int i=0;i<len;i++)ans2[i]=-MN; for(int i=1;i<len;i++) { int x=a[i].pos,k=a[i].v; int p=find(sa[x-1]),q=find(sa[x]); ans1[k]+=(long long)size[p]*size[q]; Union(p,q); ans2[k]=max(ans2[k],ans[q]); } for(int i=len-2;~i;i--) { ans1[i]+=ans1[i+1]; if(ans1[i+1]) ans2[i]=max(ans2[i],ans2[i+1]); } for(int i=0;i<len;i++)printf("%lld %lld\n",ans1[i],ans1[i]?ans2[i]:0); return 0; }