BZOJ3879: SvT
后缀数组裸题,每次的查询单调栈扫一遍就完了。为什么要写虚后缀树= =后缀数组不是自带虚树的结构么= =
#include<cstdio> #include<algorithm> using namespace std; typedef long long ll; const int N=5e5+5; typedef int arr[N]; arr sa,r,f[19]; void pre(char*s,int n){ static arr c,t; for(int i=0;i<n;++i) ++c[s[i]]; for(int i=1;i<127;++i) c[i]+=c[i-1]; for(int i=n-1;~i;--i) sa[--c[s[i]]]=i; for(int i=1;i<n;++i) r[sa[i]]=r[sa[i-1]]+(s[sa[i]]!=s[sa[i-1]]); for(int j=1;;j<<=1){ int k=j,m=r[sa[n-1]]+1; if(m==n)break; for(int i=0;i<j;++i) t[i]=n-j+i; for(int i=0;i<n;++i) if(sa[i]>=j) t[k++]=sa[i]-j; for(int i=0;i<m;++i) c[i]=0; for(int i=0;i<n;++i) ++c[r[i]]; for(int i=1;i<m;++i) c[i]+=c[i-1]; for(int i=n-1;~i;--i) sa[--c[r[t[i]]]]=t[i]; for(int i=0;i<n;++i) t[i]=r[i]; r[sa[0]]=0; for(int i=1;i<n;++i) r[sa[i]]=r[sa[i-1]]+(t[sa[i]]!=t[sa[i-1]]||t[sa[i]+j]!=t[sa[i-1]+j]); } } bool foo(int i,int j){return r[i]<r[j];} int ask(int i,int j){ int k=__lg(j-i+1); return min(f[k][i],f[k][j-(1<<k)+1]); } int main(){ int n,q,m; static char s[N]; scanf("%d%d%s",&n,&q,s); pre(s,n+1); for(int i=0,j=0;i<n;++i){ if(j)--j; while(s[i+j]==s[sa[r[i]-1]+j]) ++j; f[0][r[i]]=j; } for(int j=1;1<<j<n;++j) for(int i=1;i+(1<<j)-1<=n;++i) f[j][i]=min(f[j-1][i],f[j-1][i+(1<<j-1)]); while(q--){ static arr a,h,t; static ll z[N]; scanf("%d",&m); for(int j=0;j<m;++j) scanf("%d",a+j),--a[j]; sort(a,a+m,foo); m=unique(a,a+m)-a; for(int j=1;j<m;++j) h[j]=ask(r[a[j-1]]+1,r[a[j]]); h[m]=-1; for(int j=0;j<m;++j) z[j]=1; ll e=0; for(int i=0,j=1;j<=m;++j){ for(;i&&h[j]<=h[t[i]];--i){ e+=h[t[i]]*z[t[i-1]]*z[t[i]]; z[t[i-1]]+=z[t[i]]; } t[++i]=j; } printf("%lld\n",e); } }