1. 程式人生 > >「luogu2414」[NOI2011]阿貍的打字機

「luogu2414」[NOI2011]阿貍的打字機

name clas 阿貍的打字機 trie == log names col queue

建出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 }

「luogu2414」[NOI2011]阿貍的打字機