zoj千题计划312:bzoj3879: SvT(后缀数组+st表+单调栈)
Posted 日拱一卒 功不唐捐
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了zoj千题计划312:bzoj3879: SvT(后缀数组+st表+单调栈)相关的知识,希望对你有一定的参考价值。
https://www.lydsy.com/JudgeOnline/problem.php?id=3879
把所有的后缀取出,按rank排序
求出相邻两个后缀的lcp
每个后缀对答案的贡献就是 与在它之前的后缀的lcp之和
维护一个单调递增的栈,记录栈中元素的lcp之和 即可
#include<cstdio> #include<iostream> #include<algorithm> using namespace std; #define N 500001 #define M 3000001 int n,m,mm; char s[N]; int a[N]; int b[M],r[N]; int v[N]; int p,q=1,k; int sa[2][N],rk[2][N]; int height[N],h[N]; int st[N][16]; int Log[N]; int ST[N],top; int num[N],val[N]; void read(int &x) { x=0; char c=getchar(); while(!isdigit(c)) c=getchar(); while(isdigit(c)) { x=x*10+c-‘0‘; c=getchar(); } } void mul(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(k=1;k<n;k<<=1,swap(p,q)) mul(sa[p],rk[p],sa[q],rk[q]); } void get_height() { int k=0,j; for(int i=1;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--; } } void prest() { for(int i=2;i<=n;++i) st[i][0]=height[i]; for(int i=1,k=2;i<=15;++i,k<<=1) for(int j=2;j+k-1<=n;++j) st[j][i]=min(st[j][i-1],st[j+k/2][i-1]); } int get(int i,int j) { i++; int l=Log[j-i+1]; return min(st[i][l],st[j-(1<<l)+1][l]); } void solve() { for(int i=1;i<=mm;++i) r[i]=rk[p][b[i]]; sort(r+1,r+mm+1); for(int i=2;i<=mm;++i) h[i]=get(r[i-1],r[i]); top=0; int tmp_num; long long now=0,ans=0; for(int i=2;i<=mm;++i) { tmp_num=0; while(top && h[i]<=h[ST[top]]) { now-=1LL*num[top]*val[top]; tmp_num+=num[top--]; } tmp_num++; ST[++top]=i; num[top]=tmp_num; val[top]=h[i]; now+=1LL*tmp_num*h[i]; ans+=now; } cout<<ans<<‘\n‘; } int main() { int T; read(n); read(T); for(int i=2;i<=n;++i) Log[i]=Log[i>>1]+1; scanf("%s",s+1); for(int i=1;i<=n;++i) a[i]=s[i]-‘a‘+1; presa(); get_height(); prest(); while(T--) { read(m); for(int i=1;i<=m;++i) read(b[i]); sort(b+1,b+m+1); mm=unique(b+1,b+m+1)-b-1; solve(); } }
以上是关于zoj千题计划312:bzoj3879: SvT(后缀数组+st表+单调栈)的主要内容,如果未能解决你的问题,请参考以下文章