「luogu2414」[NOI2011]阿狸的打字机

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

 

posted @ 2018-03-14 10:21  Cupcake  阅读(120)  评论(0编辑  收藏  举报