bzoj千题计划257:bzoj4199: [Noi2015]品酒大会
http://www.lydsy.com/JudgeOnline/problem.php?id=4199
求出后缀数组的height
从大到小枚举,合并
维护组内 元素个数,最大、次大、最小、次小
#include<cstdio> #include<vector> #include<cstring> #include<iostream> #include<algorithm> using namespace std; #define N 300001 char s[N]; int n,a[N],b[N]; int p,q=1; int v[N]; int sa[2][N],rk[2][N],height[N]; vector<int>V[N]; int fa[N],siz[N]; long long sum[N],mx[N]; int mx1[N],mx2[N],mi1[N],mi2[N]; int MX1,MX2,MI1,MI2; void read (int &x) { x=0; int f=1; char c=getchar(); while(!isdigit(c)) { if(c=='-') f=-1; c=getchar(); } while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); } x*=f; } void mul(int k,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(int k=1;k<n;k<<=1,swap(p,q)) mul(k,sa[p],rk[p],sa[q],rk[q]); } void get_height() { int j; for(int i=1,k=0;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--; } } int find(int i) { return fa[i]==i ? i : fa[i]=find(fa[i]); } void unionn(int x,int y,int i) { x=find(x); y=find(y); sum[i]+=1LL*siz[x]*siz[y]; siz[y]+=siz[x]; if(mx2[x]>=mx1[y]) { mx2[y]=mx2[x]; mx1[y]=mx1[x]; } else { if(mx2[x]>mx2[y]) mx2[y]=mx2[x]; if(mx1[x]>=mx1[y]) { mx2[y]=mx1[y]; mx1[y]=mx1[x]; } else if(mx1[x]>mx2[y]) mx2[y]=mx1[x]; } if(mi2[x]<=mi1[y]) { mi2[y]=mi2[x]; mi1[y]=mi1[x]; } else { if(mi2[x]<mi2[y]) mi2[y]=mi2[x]; if(mi1[x]<=mi1[y]) { mi2[y]=mi1[y]; mi1[y]=mi1[x]; } else if(mi1[x]<mi2[y]) mi2[y]=mi1[x]; } mx[i]=max(mx[i],max(1LL*mx1[y]*mx2[y],1LL*mi1[y]*mi2[y])); fa[x]=y; } void solve() { for(int i=1;i<=n;++i) { fa[i]=i; siz[i]=1; mx[i]=-1e18; mx1[i]=b[i]; mx2[i]=-1e9; mi1[i]=b[i]; mi2[i]=1e9; } for(int i=2;i<=n;++i) V[height[i]].push_back(i); int s,w; for(int i=n;i;--i) { s=V[i].size(); for(int j=0;j<s;++j) { w=V[i][j]; if(find(sa[p][w-1])!=find(sa[p][w])) unionn(sa[p][w-1],sa[p][w],i); if(w<n && height[w+1]>=i && find(sa[p][w])!=find(sa[p][w+1])) unionn(sa[p][w+1],sa[p][w],i); } } for(int i=n-1;i;--i) { sum[i]+=sum[i+1]; mx[i]=max(mx[i],mx[i+1]); } cout<<1LL*n*(n-1)/2<<' '<<max(1LL*MX1*MX2,1LL*MI1*MI2)<<'\n'; for(int i=1;i<n;++i) { cout<<sum[i]<<' '; if(!sum[i]) cout<<0<<'\n'; else cout<<mx[i]<<'\n'; } } int main() { scanf("%d",&n); scanf("%s",s+1); for(int i=1;i<=n;++i) a[i]=s[i]-'a'+1; MX1=MX2=-1e9; MI1=MI2=1e9; for(int i=1;i<=n;++i) { read(b[i]); if(b[i]>=MX1) { MX2=MX1; MX1=b[i]; } else if(b[i]>MX2) MX2=b[i]; if(b[i]<=MI1) { MI2=MI1; MI1=b[i]; } else if(b[i]<MI2) MI2=b[i]; } presa(); get_height(); solve(); }