建出AC自动机,获得fail树,发现问题转化成求以x为根的子树中有多少个属于y串的节点。
求出fail树的dfs序,由dfs序的性质可知以x为根的子树在dfs序上是连续的。
在trie树中跑一边dfs,dfs过程中用树状数组统计答案即可。
注意fail树的节点数是tot+1。
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int N=100010; 4 char ss[N]; 5 int n,m,tot,spos[N]; //spos[i]:串i在trie树中的位置 6 int pre[N],ch[N][26],fail[N]; 7 int qx[N],qy[N],ans[N],bit[N]; 8 vector<int>g[N],curq[N]; 9 inline void build_trie(char* s){ 10 int l=strlen(s),now=0; 11 for(int i=0;i<l;i++){ 12 if(s[i]==‘B‘) now=pre[now]; 13 else if(s[i]==‘P‘) spos[++n]=now; 14 else{ 15 int c=s[i]-‘a‘; 16 if(!ch[now][c]) ch[now][c]=++tot,pre[tot]=now; 17 now=ch[now][c]; 18 } 19 } 20 return; 21 } 22 inline void build_fail(){ 23 queue<int>q; 24 for(int i=0;i<26;i++)if(ch[0][i]){ 25 q.push(ch[0][i]); 26 g[0].push_back(ch[0][i]); 27 } 28 int x; 29 while(!q.empty()){ 30 x=q.front();q.pop(); 31 for(int i=0;i<26;i++)if(ch[x][i]){ 32 q.push(ch[x][i]); 33 int j=fail[x]; 34 while(j&&!ch[j][i]) j=fail[j]; 35 fail[ch[x][i]]=ch[j][i]; 36 g[ch[j][i]].push_back(ch[x][i]); 37 } 38 } 39 return; 40 } 41 int fa[N],id[N],siz[N],dfn; 42 void dfs(int k,int father){ 43 id[k]=++dfn,fa[k]=father,siz[k]=1; 44 for(int i=0;i<g[k].size();i++){ 45 int x=g[k][i]; 46 if(x==father) continue; 47 dfs(x,k); 48 siz[k]+=siz[x]; 49 } 50 return; 51 } 52 inline int lowbit(int k){return k&(-k);} 53 inline void bitadd(int pos,int x){ 54 while(pos<=tot+1) bit[pos]+=x,pos+=lowbit(pos); 55 return; 56 } 57 inline int bitque(int pos){ 58 int ans=0; 59 while(pos) ans+=bit[pos],pos-=lowbit(pos); 60 return ans; 61 } 62 void dfs_trie(int k){ 63 bitadd(id[k],1); 64 for(int i=0;i<curq[k].size();i++){ 65 int x=curq[k][i]; 66 ans[x]=bitque(id[spos[qx[x]]]+siz[spos[qx[x]]]-1)-bitque(id[spos[qx[x]]]-1); 67 } 68 for(int i=0;i<26;i++)if(ch[k][i]){ 69 dfs_trie(ch[k][i]); 70 } 71 bitadd(id[k],-1); 72 return; 73 } 74 int main(){ 75 scanf("%s",ss); 76 build_trie(ss); 77 build_fail(); 78 dfs(0,-1); 79 scanf("%d",&m); 80 for(int i=1;i<=m;i++){ 81 scanf("%d%d",&qx[i],&qy[i]); 82 curq[spos[qy[i]]].push_back(i); 83 } 84 dfs_trie(0); 85 for(int i=1;i<=m;i++) printf("%d\n",ans[i]); 86 return 0; 87 }