[BZOJ]4199: [Noi2015]品酒大会(后缀数组+笛卡尔树)
Time Limit: 10 Sec Memory Limit: 512 MB
Description
Input
Output
Sample Input
10
ponoiiipoi
2 1 4 7 4 8 3 6 4 7
Sample Output
45 56
10 56
3 32
0 0
0 0
0 0
0 0
0 0
0 0
0 0
HINT
Solution
先求出后缀数组,两个后缀的最长公共前缀是它们之间height的最小值,对height建笛卡尔树,树上维护最大最小值即可。
Code
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define ll long long inline int read() { int x,f=1;char c; while((c=getchar())<'0'||c>'9')if(c=='-')f=0; for(x=c-'0';(c=getchar())>='0'&&c<='9';)x=x*10+c-'0'; return f?x:-x; } #define MN 300000 int v[MN+5],ar[MN*4+10],*sa=ar,*nsa=sa+MN+2,*rk=nsa+MN+2,*nrk=rk+MN+2,h[MN+5]; int a[MN+5],z[MN+5],zn,lc[MN+5],rc[MN+5],sz[MN+5],mx[MN+5],mn[MN+5]; ll f1[MN+5],f2[MN+5]; char s[MN+5]; void dfs(int x) { if(!x)return; int l=lc[x],r=rc[x]; dfs(l);dfs(r); if(!l)l=MN+1,sz[l]=1,mx[l]=mn[l]=a[sa[x-1]]; if(!r)r=MN+2,sz[r]=1,mx[r]=mn[r]=a[sa[x]]; f1[h[x]]+=1LL*sz[l]*sz[r]; f2[h[x]]=max(f2[h[x]],max(max(1LL*mn[l]*mn[r],1LL*mn[l]*mx[r]), max(1LL*mx[l]*mn[r],1LL*mx[l]*mx[r]))); sz[x]=sz[l]+sz[r]; mn[x]=min(mn[l],mn[r]); mx[x]=max(mx[l],mx[r]); } int main() { int n=read(),l,i,x; scanf("%s",s+1); for(i=1;i<=n;++i)a[i]=read(); for(i=1;i<=n;++i)++v[s[i]]; for(i='a';i<='z';++i)v[i]+=v[i-1]; for(i=1;i<=n;++i)sa[v[s[i]]--]=i; for(i=1;i<=n;++i)rk[sa[i]]=rk[sa[i-1]]+(s[sa[i]]!=s[sa[i-1]]); for(l=1;l<n;l<<=1,swap(sa,nsa),swap(rk,nrk)) { for(i=1;i<=n;++i)v[rk[sa[i]]]=i; for(i=n;i;--i)if(sa[i]>l)nsa[v[rk[sa[i]-l]]--]=sa[i]-l; for(i=0;i<l;++i)nsa[v[rk[n-i]]--]=n-i; for(i=1;i<=n;++i)nrk[nsa[i]]=nrk[nsa[i-1]]+(rk[nsa[i]]!=rk[nsa[i-1]]||rk[nsa[i]+l]!=rk[nsa[i-1]+l]); } for(i=1,l=0;i<=n;++i,l?--l:0) if(rk[i]>1){for(x=sa[rk[i]-1];s[i+l]==s[x+l];++l);h[rk[i]]=l;} for(i=2;i<=n;++i) { while(zn&&h[i]<h[z[zn]])lc[i]=z[zn--]; rc[z[zn]]=i;z[++zn]=i; } memset(f2,200,sizeof(f2)); dfs(z[1]); for(i=n;i--;)f1[i]+=f1[i+1],f2[i]=max(f2[i],f2[i+1]); for(i=0;i<n;++i)printf("%lld %lld\n",f1[i],f1[i]?f2[i]:0); }