求出S串的后缀树,则两个后缀的lcp等于其lca到根的距离
对于每次询问,对这些节点构造虚树,然后树形DP即可
#include<cstdio> #include<algorithm> using std::sort; typedef long long ll; const int inf=1<<25,S=28,N=1000010; const ll P=23333333333333333LL; char tmp[N],ch; int text[N],root,last,pos,need,remain,acnode,ace,aclen; int Q,n,m,i,x,y; int dfn,st[N],en[N],id[N],d[N],f[N],son[N],size[N],top[N]; int a[N],q[N],g[N],nxt[N],v[N],ed,tot,t; bool vip[N],vis[N]; ll ans; inline bool cmp(int x,int y){return st[x]<st[y];} inline void read(int&a){char c;while(!(((c=getchar())>='0')&&(c<='9')));a=c-'0';while(((c=getchar())>='0')&&(c<='9'))(a*=10)+=c-'0';} inline int min(int a,int b){return a<b?a:b;} inline void swap(int&a,int&b){int c=a;a=b;b=c;} inline void add(int x,int y){v[++ed]=y;nxt[ed]=g[x];g[x]=ed;} struct node{int st,en,lk,son[S];inline int len(){return min(en,pos+1)-st;}}tree[N]; inline int new_node(int st,int en=inf){return tree[++last].st=st,tree[last].en=en,last;} inline int acedge(){return text[ace];} inline void addedge(int node){ if(need)tree[need].lk=node; need=node; } inline bool down(int node){ if(aclen>=tree[node].len())return ace+=tree[node].len(),aclen-=tree[node].len(),acnode=node,1; return 0; } inline void init(){ need=last=remain=ace=aclen=0; root=acnode=new_node(pos=-1,-1); } inline void extend(int c){ text[++pos]=c;need=0;remain++; while(remain){ if(!aclen)ace=pos; if(!tree[acnode].son[acedge()])tree[acnode].son[acedge()]=new_node(pos),addedge(acnode); else{ int nxt=tree[acnode].son[acedge()]; if(down(nxt))continue; if(text[tree[nxt].st+aclen]==c){aclen++;addedge(acnode);break;} int split=new_node(tree[nxt].st,tree[nxt].st+aclen); tree[acnode].son[acedge()]=split; tree[split].son[c]=new_node(pos); tree[nxt].st+=aclen; tree[split].son[text[tree[nxt].st]]=nxt; addedge(split); } remain--; if(acnode==root&&aclen)aclen--,ace=pos-remain+1; else acnode=tree[acnode].lk?tree[acnode].lk:root; } } void dfs(int x,int sum){ d[x]=sum+=tree[x].len();size[x]=1; if(tree[x].en==inf)id[pos-sum+2]=x; st[x]=++dfn; for(int i=0;i<S;i++)if(tree[x].son[i]){ add(x,tree[x].son[i]); f[tree[x].son[i]]=x; dfs(tree[x].son[i],sum); size[x]+=size[tree[x].son[i]]; if(size[tree[x].son[i]]>size[son[x]])son[x]=tree[x].son[i]; } en[x]=dfn; } void dfs2(int x,int y){ top[x]=y; if(son[x])dfs2(son[x],y); for(int i=g[x];i;i=nxt[i])if(v[i]!=son[x]&&v[i]!=f[x])dfs2(v[i],v[i]); } inline int lca(int x,int y){ for(;top[x]!=top[y];x=f[top[x]])if(d[top[x]]<d[top[y]])swap(x,y); return d[x]<d[y]?x:y; } inline ll mul(ll a,int b){ll t=0;for(;b;b>>=1,(a<<=1)%=P)if(b&1)(t+=a)%=P;return t;} void dp(int x){ size[x]=0; ll tmp=0; for(int i=g[x];i;i=nxt[i]){ dp(v[i]); (tmp+=(ll)size[x]*size[v[i]]%P)%=P; size[x]+=size[v[i]]; } (ans+=mul(tmp,d[x]))%=P; size[x]+=vip[x]; } int main(){ init(); read(n),read(Q); for(i=1;i<=n;tmp[i++]=ch)while(!(((ch=getchar())>='a')&&(ch<='z'))); for(i=1;i<=n;i++)extend(tmp[i]-'a'+1);extend(27); dfs(root,0),dfs2(root,root); for(i=1;i<=last;i++)g[i]=0; while(Q--){ read(m); for(ans=tot=0,i=1;i<=m;i++){ read(x); if(!vis[x=id[x]])vis[a[++tot]=x]=vip[x]=1; } m=tot,sort(a+1,a+m+1,cmp); for(i=1;i<m;i++)if(!vis[x=lca(a[i],a[i+1])])vis[a[++tot]=x]=1; m=tot,sort(a+1,a+m+1,cmp); for(ed=0,q[t=1]=a[1],i=2;i<=m;q[++t]=a[i++]){ while(st[a[i]]<st[q[t]]||en[a[i]]>en[q[t]])t--; add(q[t],a[i]); } dp(a[1]); for(i=1;i<=m;i++)vis[a[i]]=vip[a[i]]=g[a[i]]=0; printf("%lld ",ans); } return 0; }