题目
思路
也就是询问一些后缀的前缀
然后翻转变为查询前缀的后缀
建立后缀自动机
对于一个串由于在
树上爬时候是它的后缀
那么预处理每个前缀
代表结点
那么两个前缀
最长的
就是
然后以
为
的贡献为
其中
为
的不同儿子
当然也可以这样:
也就是把每一对的
拆分计算
然后建立虚树即可
代码
#include<set>
#include<map>
#include<stack>
#include<ctime>
#include<cstdio>
#include<queue>
#include<cmath>
#include<vector>
#include<cstring>
#include<climits>
#include<iostream>
#include<algorithm>
using namespace std;
#define LL long long
#define ULL unsigned long long
int read(){
int f=1,x=0;char c=getchar();
while(c<'0'||'9'<c){if(c=='-')f=-1;c=getchar();}
while('0'<=c&&c<='9'){x=x*10+c-'0';c=getchar();}
return f*x;
}
#define MAXN 800000
#define INF 0x3f3f3f3f
int scnt,Root,lst,maxlen[MAXN+5],nxt[MAXN+5][26],fail[MAXN+5],ed[MAXN+5];
void Init(){
scnt=Root=lst=1;
return ;
}
void Extend(int c,int id){
int p=lst,cur=++scnt;
ed[id]=cur;
maxlen[cur]=maxlen[p]+1,lst=cur;
while(p&&!nxt[p][c])
nxt[p][c]=cur,p=fail[p];
if(!p){
fail[cur]=1;
return ;
}
int q=nxt[p][c];
if(maxlen[q]==maxlen[p]+1){
fail[cur]=q;
return ;
}
int clone=++scnt;
maxlen[clone]=maxlen[p]+1;
memcpy(nxt[clone],nxt[q],sizeof(nxt[q]));
fail[clone]=fail[q];
fail[cur]=fail[q]=clone;
while(p&&nxt[p][c]==q)
nxt[p][c]=clone,p=fail[p];
return ;
}
vector<int> E[MAXN+5],G[MAXN+5];
int lg2[MAXN+5],dcnt,dfn[MAXN+5],dep[MAXN+5],st[20][MAXN+5];
void DFS(int u){
dfn[u]=++dcnt,st[0][dcnt]=u;
for(int i=0;i<(int)E[u].size();i++){
int v=E[u][i];
dep[v]=dep[u]+1;
DFS(v);
st[0][++dcnt]=u;
}
return ;
}
void Prepare(){
for(int i=2;i<=dcnt;i++)
lg2[i]=lg2[i>>1]+1;
for(int i=1;i<=19;i++)
for(int j=1;j<=dcnt;j++){
int x=st[i-1][j],y=st[i-1][j+(1<<(i-1))];
st[i][j]=(dep[x]<dep[y]?x:y);
}
return ;
}
int Lca(int u,int v){
u=dfn[u],v=dfn[v];
if(u>v) swap(u,v);
int i=lg2[v-u+1],a=st[i][u],b=st[i][v-(1<<i)+1];
return dep[a]<dep[b]?a:b;
}
LL ans;
int siza[MAXN+5],sizb[MAXN+5];
int acnt,a[MAXN+5],tp,stk[MAXN+5];
bool vis[MAXN+5],va[MAXN+5],vb[MAXN+5];
void DFS2(int u,int ff){
siza[u]=va[u],sizb[u]=vb[u];
for(int i=0;i<(int)G[u].size();i++){
int v=G[u][i];
DFS2(v,u),siza[u]+=siza[v],sizb[u]+=sizb[v];
}
ans+=1ll*siza[u]*sizb[u]*(maxlen[u]-maxlen[ff]);
return ;
}
char S[MAXN+5];
bool cmp(int a,int b){return dfn[a]<dfn[b];}
int main(){
int n=read(),q=read();
scanf("%s",S+1);
Init();
for(int i=n;i>=1;i--)
Extend(S[i]-'a',i);
for(int i=2;i<=scnt;i++)
E[fail[i]].push_back(i);
DFS(Root);
Prepare();
for(int t=1;t<=q;t++){
acnt=0;
int k=read(),l=read();
for(int i=1;i<=k;i++){
int x=read();
a[++acnt]=ed[x],vis[ed[x]]=1,va[ed[x]]=1;
}
for(int i=1;i<=l;i++){
int x=read();
a[++acnt]=ed[x],vis[ed[x]]=1,vb[ed[x]]=1;
}
sort(a+1,a+acnt+1,cmp);
for(int tmp=acnt,i=1;i<tmp;i++){
int lca=Lca(a[i],a[i+1]);
if(!vis[lca])
vis[lca]=1,a[++acnt]=lca;
}
sort(a+1,a+acnt+1,cmp);
tp=0,stk[++tp]=a[1];
for(int i=2;i<=acnt;i++){
if(a[i]==a[i-1]) continue;
while(tp>1&&Lca(stk[tp],a[i])!=stk[tp])
tp--;
G[stk[tp]].push_back(a[i]);
//printf("%d %d\n",stk[tp],a[i]);
stk[++tp]=a[i];
}
ans=0,DFS2(a[1],0);
printf("%lld\n",ans);
for(int i=1;i<=acnt;i++)
G[a[i]].clear(),vis[a[i]]=0,va[a[i]]=0,vb[a[i]]=0;
}
return 0;
}