将每个串正着插入Trie A中,倒着插入Trie B中。
并求出每个串在A,B中的dfs序。
每次查询等价于查询在A中dfs序在[la,ra]之间,在B中dfs序在[lb,rb]之间的串的个数,用主席树维护即可。
#include<cstdio> const int S=2000010,N=2010,M=N*22; char s[S],ch; int n,m,i,j,k,posa[N],posb[N],g[S],v[N],nxt[N],ed,la,lb,ra,rb,ans; inline void read(){ while(!(((ch=getchar())>='a')&&(ch<='z'))); s[k=1]=(ch-'a'+ans)%26; while(((ch=getchar())>='a')&&(ch<='z'))s[++k]=(ch-'a'+ans)%26; } inline void add(int x,int y){v[++ed]=y;nxt[ed]=g[x];g[x]=ed;} struct Trie{ int tot,son[S][26],st[S],en[S],dfn; inline int ins0(){ int x=0; for(int i=1;i<=k;i++){ if(!son[x][s[i]])son[x][s[i]]=++tot; x=son[x][s[i]]; } return x; } inline int ins1(){ int x=0; for(int i=k;i;i--){ if(!son[x][s[i]])son[x][s[i]]=++tot; x=son[x][s[i]]; } return x; } void dfs(int x){ st[x]=++dfn; for(int i=0;i<26;i++)if(son[x][i])dfs(son[x][i]); en[x]=dfn; } inline void ask0(){ int x=0; for(int i=1;i<=k;i++){ if(!son[x][s[i]]){la=ra=0;return;} x=son[x][s[i]]; } la=st[x],ra=en[x]; } inline void ask1(){ int x=0; for(int i=k;i;i--){ if(!son[x][s[i]]){lb=rb=0;return;} x=son[x][s[i]]; } lb=st[x],rb=en[x]; } }A,B; int l[M],r[M],val[M],tot,T[S]; int ins(int x,int a,int b,int c){ int y=++tot;val[y]=val[x]+1; if(a==b)return y; int mid=(a+b)>>1; if(c<=mid)l[y]=ins(l[x],a,mid,c),r[y]=r[x];else l[y]=l[x],r[y]=ins(r[x],mid+1,b,c); return y; } int ask(int x,int a,int b){ if(!x)return 0; if(lb<=a&&b<=rb)return val[x]; int mid=(a+b)>>1,t=0; if(lb<=mid)t=ask(l[x],a,mid); if(rb>mid)t+=ask(r[x],mid+1,b); return t; } int main(){ scanf("%d",&n); for(i=1;i<=n;i++){ read(); posa[i]=A.ins0(); posb[i]=B.ins1(); } A.dfs(0),B.dfs(0); for(i=1;i<=n;i++)add(A.st[posa[i]],B.st[posb[i]]); for(i=1;i<=A.dfn;i++)for(T[i]=T[i-1],j=g[i];j;j=nxt[j])T[i]=ins(T[i],1,B.dfn,v[j]); scanf("%d",&m); while(m--){ read(),A.ask0(); read(),B.ask1(); if(la&&lb)ans=ask(T[ra],1,B.dfn)-ask(T[la-1],1,B.dfn);else ans=0; printf("%d\n",ans); } return 0; }