后缀数组裸题,每次的查询单调栈扫一遍就完了。为什么要写虚后缀树= =后缀数组不是自带虚树的结构么= =
#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);
}
}