传送门
题解:
后缀排序,预处理LCP询问。
单调队列,合并两个块的时候算答案。
没了。
好写常数还小。
代码:
#include<bits/stdc++.h>
#define ll long long
#define re register
#define gc get_char
#define cs const
namespace IO{
inline char get_char(){
static cs int Rlen=1<<22|1;
static char buf[Rlen],*p1,*p2;
return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
}
inline int get_s(char *s){
int len=0;char c;
while(isspace(c=gc()));
while(s[len++]=c,!isspace(c=gc())&&c!=EOF);
s[len]='\0';return len;
}
template<typename T>
inline T get(){
char c;
while(!isdigit(c=gc()));T num=c^48;
while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
return num;
}
inline int getint(){return get<int>();}
}
using namespace IO;
using std::cerr;
using std::cout;
cs int N=5e5+5;
int n;
char s[N];
int sa[N],rk[N],ht[N];
inline void radix_sort(int *x,int *y,int m,int n){
static int bin[N];
memset(bin+1,0,sizeof(int)*m);
for(int re i=1;i<=n;++i)++bin[x[i]];
for(int re i=1;i<=m;++i)bin[i]+=bin[i-1];
for(int re i=n;i;--i)sa[bin[x[y[i]]]--]=y[i];
}
inline void init(){
int *x=rk,*y=ht;
for(int re i=1;i<=n;++i)x[i]=s[i],y[i]=i;
radix_sort(x,y,128,n);
int m=128;
for(int re i=1,cnt=0;cnt<n;i<<=1){
cnt=0;
for(int re j=n-i+1;j<=n;++j)y[++cnt]=j;
for(int re j=1;j<=n;++j)if(sa[j]>i)y[++cnt]=sa[j]-i;
radix_sort(x,y,m,n);std::swap(x,y);
x[sa[1]]=1,cnt=1;
for(int re j=2;j<=n;++j)
x[sa[j]]=(y[sa[j]]==y[sa[j-1]]&&y[sa[j]+i]==y[sa[j-1]+i])?cnt:++cnt;
m=cnt;
}
for(int re i=1;i<=n;++i)rk[sa[i]]=i;
for(int re i=1,j,k=0;i<=n;ht[rk[i++]]=k)
for(k?--k:0,j=sa[rk[i]-1];s[i+k]==s[j+k];++k);
}
int mn[19][N],Log[N];
inline void init_RMQ(){
Log[0]=-1;
for(int re i=1;i<=n;++i)mn[0][i]=ht[i],Log[i]=Log[i>>1]+1;
for(int re i=1;(1<<i)<=n;++i)
for(int re j=1;j+(1<<i)-1<=n;++j)
mn[i][j]=std::min(mn[i-1][j],mn[i-1][j+(1<<i-1)]);
}
inline int qy(int l,int r){
int t=Log[r-l+1];
return std::min(mn[t][l],mn[t][r-(1<<t)+1]);
}
inline int lcp(int a,int b){
a=rk[a],b=rk[b];
if(a>b)std::swap(a,b);
return qy(a+1,b);
}
int m;
int q[N],h[N],cnt[N];
int st[N],top;
inline bool cmp(int a,int b){return rk[a]<rk[b];}
signed main(){
// freopen("svt.in","r",stdin);
n=getint(),m=getint();
get_s(s+1),init(),init_RMQ();
while(m--){
n=getint();
for(int re i=1;i<=n;++i)q[i]=getint();
std::sort(q+1,q+n+1,cmp);
n=std::unique(q+1,q+n+1)-q-1;
for(int re i=1;i<n;++i)h[i]=lcp(q[i],q[i+1]);h[n]=-1;
for(int re i=0;i<n;++i)cnt[i]=1;
top=0;ll ans=0;
for(int re i=1;i<=n;++i){
while(top&&h[i]<=h[st[top]]){
ans+=(ll)h[st[top]]*cnt[st[top-1]]*cnt[st[top]];
cnt[st[top-1]]+=cnt[st[top]];
--top;
}
st[++top]=i;
}
cout<<ans<<"\n";
}
return 0;
}