bzoj千题计划313: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=,k;
int sa[][N],rk[][N]; int height[N],h[N];
int st[N][]; int Log[N]; int ST[N],top;
int num[N],val[N]; void read(int &x)
{
x=; char c=getchar();
while(!isdigit(c)) c=getchar();
while(isdigit(c)) { x=x*+c-''; c=getchar(); }
} void mul(int *sa,int *rk,int *SA,int *RK)
{
for(int i=;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+;i<=n;++i) SA[v[rk[i]]--]=i;
for(int i=;i<=n;++i) RK[SA[i]]=RK[SA[i-]]+(rk[SA[i]]!=rk[SA[i-]] || rk[SA[i]+k]!=rk[SA[i-]+k]);
} void presa()
{
for(int i=;i<=n;++i) v[a[i]]++;
for(int i=;i<=;++i) v[i]+=v[i-];
for(int i=;i<=n;++i) sa[p][v[a[i]]--]=i;
for(int i=;i<=n;++i) rk[p][sa[p][i]]=rk[p][sa[p][i-]]+(a[sa[p][i]]!=a[sa[p][i-]]);
for(k=;k<n;k<<=,swap(p,q)) mul(sa[p],rk[p],sa[q],rk[q]);
} void get_height()
{
int k=,j;
for(int i=;i<=n;++i)
{
j=sa[p][rk[p][i]-];
while(a[i+k]==a[j+k]) k++;
height[rk[p][i]]=k;
if(k) k--;
}
} void prest()
{
for(int i=;i<=n;++i) st[i][]=height[i];
for(int i=,k=;i<=;++i,k<<=)
for(int j=;j+k-<=n;++j)
st[j][i]=min(st[j][i-],st[j+k/][i-]);
} int get(int i,int j)
{
i++;
int l=Log[j-i+];
return min(st[i][l],st[j-(<<l)+][l]);
} void solve()
{
for(int i=;i<=mm;++i) r[i]=rk[p][b[i]];
sort(r+,r+mm+);
for(int i=;i<=mm;++i) h[i]=get(r[i-],r[i]);
top=;
int tmp_num;
long long now=,ans=;
for(int i=;i<=mm;++i)
{
tmp_num=;
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=;i<=n;++i) Log[i]=Log[i>>]+;
scanf("%s",s+);
for(int i=;i<=n;++i) a[i]=s[i]-'a'+;
presa();
get_height();
prest();
while(T--)
{
read(m);
for(int i=;i<=m;++i) read(b[i]);
sort(b+,b+m+);
mm=unique(b+,b+m+)-b-;
solve();
}
}
上一篇:【JavaScript流程控制语句的用法及练习】


下一篇:SqlServer 数据库进行定时自动的执行脚本