AC自动机和KMP

AC自动机存储一个字符串的集合,把他叫做T.用i(s)表示字符串s的代表节点. 用s(i)表示节点i的代表字符串.

构建需要的时间是 $O(nc)$ 的,n为字符个数,c为字符集的大小.

AC自动机的性质.

1.从根到一个节点的路径是T中某些字串的前缀. (trie 基本性质)

2.从一个节点到叶节点的路径是这个集合中某一个(如果T的元素不可重复)字串的后缀.(trie 基本性质)

3.fail指针构成一棵fail树,树上父亲-儿子节点的关系为: 设父节点代表的字串为f,子节点为s,那么:

  f是s的后缀,但不一定是s的前缀. (fail树基本性质)

4.如果s(i)是s(j)的后缀,那么在fail树上,i一定是j的祖先. (fail树基本性质)

 

AC自动机的一个用处就是匹配.从trie的根节点(经过fail树边/trie树边)到点i的路径条数就是能匹配到点i的字符串个数.

AC自动机的另一个用处是有了fail树以后,我们可以处理一些后缀相关的东西.此类题目大多具有自我匹配的特点,即用T中的字符串匹配T中的元素.


AC USACO 2015 Feb. Gold T2 Censor

一道模板题.....

  1 #include <cstdio>
  2 #include <fstream>
  3 #include <iostream>
  4  
  5 #include <cstdlib>
  6 #include <cstring>
  7 #include <algorithm>
  8 #include <cmath>
  9  
 10 #include <queue>
 11 #include <vector>
 12 #include <map>
 13 #include <set>
 14 #include <stack>
 15 #include <list>
 16  
 17 typedef unsigned int uint;
 18 typedef long long int ll;
 19 typedef unsigned long long int ull;
 20 typedef double db;
 21  
 22 using namespace std;
 23  
 24 inline int getint()
 25 {
 26     int res=0;
 27     char c=getchar();
 28     bool mi=false;
 29     while(c<'0' || c>'9') mi=(c=='-'),c=getchar();
 30     while('0'<=c && c<='9') res=res*10+c-'0',c=getchar();
 31     return mi ? -res : res;
 32 }
 33 inline ll getll()
 34 {
 35     ll res=0;
 36     char c=getchar();
 37     bool mi=false;
 38     while(c<'0' || c>'9') mi=(c=='-'),c=getchar();
 39     while('0'<=c && c<='9') res=res*10+c-'0',c=getchar();
 40     return mi ? -res : res;
 41 }
 42  
 43 db eps=1e-20;
 44 inline bool feq(db a,db b)
 45 { return fabs(a-b)<eps; }
 46 
 47 template<typename Type>
 48 inline Type avg(const Type a,const Type b)
 49 { return a+((b-a)/2); }
 50 
 51 //==============================================================================
 52 //==============================================================================
 53 //==============================================================================
 54 //==============================================================================
 55 
 56 int n,m;
 57 char S[105000];
 58 char inp[105000];
 59 
 60 struct node
 61 {
 62     node*s[26];
 63     node*trans[26];
 64     node*f;
 65     node*p; //parent.
 66     bool leaf; //is terminal ?
 67     char v; //witch character this node represent ?
 68     node()
 69     { memset(s,0,sizeof(s)); f=p=NULL; leaf=false; }
 70 }pool[105000];
 71 node*pt=pool;
 72 
 73 node*qc[105000];
 74 node*qf[105000];
 75 int qh,qt;
 76 
 77 struct Trie
 78 {
 79     node*root;
 80     Trie(){ root=pt++; root->v='*'-'a'; }
 81     
 82     void Insert(char*f,int len)
 83     {
 84         node*x=root;
 85         for(int i=0;i<len;i++)
 86         {
 87             int v=f[i]-'a';
 88             if(x->s[v]==NULL)
 89             {
 90                 x->s[v]=pt++;
 91                 x->s[v]->p=x;
 92                 x->s[v]->v=v;
 93             }
 94             x=x->s[v];
 95         }
 96         x->leaf=true;
 97     }
 98     
 99     void Construct()
100     {
101         node*x=root;
102         qh=qt=0;
103         for(int i=0;i<26;i++)
104         if(x->s[i]!=NULL)
105         {
106             x->s[i]->f=root;
107             for(int j=0;j<26;j++)
108             if(x->s[i]->s[j]!=NULL)
109                 qc[qt]=x->s[i]->s[j],qf[qt]=root,qt++;
110         }
111         
112         while(qh!=qt)
113         {
114             node*cur=qc[qh];
115             node*fp=qf[qh];
116             
117             while(fp!=root && fp->s[cur->v]==NULL) fp=fp->f;
118             if(fp->s[cur->v]!=NULL) fp=fp->s[cur->v];
119             cur->f=fp;
120             
121             for(int i=0;i<26;i++)
122                 if(cur->s[i]!=NULL)
123                     qc[qt]=cur->s[i],qf[qt]=fp,qt++;
124             
125             qh++;
126         }
127     }
128     
129     node*GetTrans(node*x,int v)
130     {
131         if(x->s[v]!=NULL)
132             return x->trans[v]=x->s[v];
133         
134         if(x->trans[v]==NULL)
135         {
136             if(x==root) return root;
137             
138             return x->trans[v]=GetTrans(x->f,v);
139         }
140         
141         return x->trans[v];
142     }
143 
144     
145     
146     void output() { output(root); }
147     void output(node*x)
148     {
149         printf("%c %02d %p %p %p 
",x->v+'a',x->v,x,x->f,x->p);
150         for(int i=0;i<26;i++)
151         if(x->s[i]!=NULL) output(x->s[i]);
152     }
153 }T;
154 
155 node*_step[105000];
156 node**step=_step+1;
157 int _prev[105000];
158 int*prev=_prev+1;
159 
160 int main()
161 {
162     freopen("censor.in","r",stdin);
163     freopen("censor.out","w",stdout);
164     
165     scanf("%s",S);
166     n=strlen(S);
167     m=getint();
168     for(int i=0;i<m;i++)
169     {
170         scanf("%s",inp);
171         T.Insert(inp,strlen(inp));
172     }
173     
174     T.Construct();
175     
176     step[-1]=T.root;
177     prev[-1]=-1;
178     for(int i=0;i<n;i++)
179     prev[i]=i-1;
180     
181     for(int i=0;i<n;i++)
182     {
183         step[i]=T.GetTrans(step[i-1],S[i]-'a');
184 
185         if(step[i]->leaf) //we found a word.
186         {
187             node*p=step[i];
188             int cur=i;
189             while(p!=T.root && cur!=-1)
190             {
191                 S[cur]=0;
192                 p=p->p;
193                 cur=prev[cur];
194             }
195             
196             step[i]=step[cur];
197             prev[i+1]=cur;
198         }
199     }
200     
201     for(int i=0;i<n;i++)
202     if(S[i]!=0)
203     printf("%c",S[i]);
204     printf("
");
205     
206     
207     return 0;
208 }
View Code

具体的,我们维护每个字符在自动机上的到达状态,然后匹配完毕后暴力删掉(用后向链表)匹配完毕的字符串,把当前状态变为删除字符串的前面一个字符的状态再接着匹配......

注意由于有指针跳跃操作,AC自动机的f转移就不能均摊O(n)了,于是要预处理trans表示转移到哪个节点(而不是沿着f跑).....

这里用了记忆化搜索呃.......

 


 

 

另一个模板.

AC BZOJ 1030

  1 #include <cstdio>
  2 #include <fstream>
  3 #include <iostream>
  4  
  5 #include <cstdlib>
  6 #include <cstring>
  7 #include <algorithm>
  8 #include <cmath>
  9  
 10 #include <queue>
 11 #include <vector>
 12 #include <map>
 13 #include <set>
 14 #include <stack>
 15 #include <list>
 16  
 17 typedef unsigned int uint;
 18 typedef long long int ll;
 19 typedef unsigned long long int ull;
 20 typedef double db;
 21  
 22 using namespace std;
 23  
 24 inline int getint()
 25 {
 26     int res=0;
 27     char c=getchar();
 28     bool mi=false;
 29     while(c<'0' || c>'9') mi=(c=='-'),c=getchar();
 30     while('0'<=c && c<='9') res=res*10+c-'0',c=getchar();
 31     return mi ? -res : res;
 32 }
 33 inline ll getll()
 34 {
 35     ll res=0;
 36     char c=getchar();
 37     bool mi=false;
 38     while(c<'0' || c>'9') mi=(c=='-'),c=getchar();
 39     while('0'<=c && c<='9') res=res*10+c-'0',c=getchar();
 40     return mi ? -res : res;
 41 }
 42  
 43 db eps=1e-20;
 44 inline bool feq(db a,db b)
 45 { return fabs(a-b)<eps; }
 46 
 47 template<typename Type>
 48 inline Type avg(const Type a,const Type b)
 49 { return a+((b-a)/2); }
 50 
 51 //==========================================================
 52 //==========================================================
 53 //==========================================================
 54 //==========================================================
 55 
 56 const int MOD=(10007);
 57 
 58 inline void add(int&a,int&b)
 59 { a=(a+b)%MOD; }
 60 
 61 
 62 struct node
 63 {
 64     char v;
 65     node*s[26];
 66     node*trans[26];    
 67     node*f;
 68     bool danger;
 69     int code;
 70     node()
 71     {
 72         memset(s,0,sizeof(s));
 73         memset(trans,0,sizeof(trans));
 74         f=NULL;
 75         danger=false;
 76     }
 77 }pool[6050];
 78 node*nt=pool;
 79 
 80 node*newnode(char v)
 81 { nt->v=v; nt->code=int(nt-pool); return nt++; }
 82 
 83 struct trie
 84 {
 85     node*root;
 86     trie(){ root=newnode('*'-'A'); }
 87     
 88     void Insert(char *f,int len)
 89     {
 90         node*cur=root;
 91         for(int i=0;i<len;i++)
 92         {
 93             int v=f[i]-'A';
 94             if(cur->s[v]==NULL)
 95                 cur->s[v]=newnode(v);
 96             cur=cur->s[v];
 97         }
 98         cur->danger=true;
 99     }
100     
101     void construct() 
102     {
103         queue<node*> q;
104         queue<node*> h;
105         
106         for(int i=0;i<26;i++)
107         if(root->s[i])
108         {
109             root->s[i]->f=root;
110             
111             for(int j=0;j<26;j++)
112             if(root->s[i]->s[j])
113             q.push(root->s[i]->s[j]),h.push(root);
114         }
115         
116         while(!q.empty())
117         {
118             node*x=q.front(); q.pop();
119             node*p=h.front(); h.pop();
120             
121             //deal with current node.
122             while(p!=root && !p->s[x->v]) p=p->f;
123             if(p->s[x->v]) p=p->s[x->v];
124             x->f=p;
125             
126             if(p->danger) x->danger=true;
127             
128             //expend sub trees.
129             for(int i=0;i<26;i++)
130             if(x->s[i]) q.push(x->s[i]),h.push(p);
131         }
132     }
133     
134     node* GetTrans(node*x,int v)
135     {
136         if(x->trans[v]) return x->trans[v];
137         else return x->trans[v]=
138         ( x->s[v] ? x->s[v] : ( x==root ? root : GetTrans(x->f,v) ) );
139     }
140 };
141 
142 int n,m;
143 char inp[200];
144 
145 trie T;
146 
147 int d[105][6050];
148 
149 int main()
150 {
151     n=getint();
152     m=getint();
153     
154     for(int i=0;i<n;i++)
155     {
156         scanf("%s",inp);
157         T.Insert(inp,strlen(inp));
158     }
159     
160     T.construct();
161     
162     d[0][0]=1;
163     for(int h=1;h<=m;h++)
164     {
165         for(node*x=pool;x<nt;x++)
166         {
167             if(x->danger) continue;
168             for(int i=0;i<26;i++)
169                 add(d[h][T.GetTrans(x,i)->code],d[h-1][x->code]);
170         }
171     }
172     
173     int res=0;
174     for(node*x=pool;x<nt;x++)
175     if(!x->danger) add(res,d[m][x->code]);
176     
177     int de=1;
178     for(int i=0;i<m;i++) 
179     de=(de*26)%MOD;
180     
181     printf("%d
",((de-res)%MOD+MOD)%MOD);
182     
183     return 0;
184 }
View Code

注意 if(p->danger) x->danger=true;这一句,用于判断某字符串是否为另一个字符串的后缀.

不加这个的话,会错掉这个数据"2 2 ABA B",正确输出51.

 注意这个题的模式串很小,那个求trans的操作实际上是 $O(n^2)$ 的.

 


 

 

AC BZOJ 3942 USACO Feb. Silver T1 Censoring

  1 #include <cstdio>
  2 #include <fstream>
  3 #include <iostream>
  4  
  5 #include <cstdlib>
  6 #include <cstring>
  7 #include <algorithm>
  8 #include <cmath>
  9  
 10 #include <queue>
 11 #include <vector>
 12 #include <map>
 13 #include <set>
 14 #include <stack>
 15 #include <list>
 16  
 17 typedef unsigned int uint;
 18 typedef long long int ll;
 19 typedef unsigned long long int ull;
 20 typedef double db;
 21  
 22 using namespace std;
 23  
 24 inline int getint()
 25 {
 26     int res=0;
 27     char c=getchar();
 28     bool mi=false;
 29     while(c<'0' || c>'9') mi=(c=='-'),c=getchar();
 30     while('0'<=c && c<='9') res=res*10+c-'0',c=getchar();
 31     return mi ? -res : res;
 32 }
 33 inline ll getll()
 34 {
 35     ll res=0;
 36     char c=getchar();
 37     bool mi=false;
 38     while(c<'0' || c>'9') mi=(c=='-'),c=getchar();
 39     while('0'<=c && c<='9') res=res*10+c-'0',c=getchar();
 40     return mi ? -res : res;
 41 }
 42  
 43 db eps=1e-20;
 44 inline bool feq(db a,db b)
 45 { return fabs(a-b)<eps; }
 46 
 47 template<typename Type>
 48 inline Type avg(const Type a,const Type b)
 49 { return a+((b-a)/2); }
 50 
 51 //==============================================================================
 52 //==============================================================================
 53 //==============================================================================
 54 //==============================================================================
 55 
 56 char a[1005000];
 57 char s[1005000];
 58 int f[1005000];
 59 int tran[1005000][26];
 60 int _pre[1005000];
 61 int*pre=_pre+1;
 62 int _state[1005000];
 63 int*state=_state+1;
 64 
 65 inline int ch(char c) { return c-'a'; }
 66 inline char revh(int k) { return (char)(k+'a'); }
 67 
 68 char res[1005000];
 69 
 70 int n,m;
 71 
 72 int main()
 73 {
 74     scanf("%s%s",s,a);
 75     n=strlen(a);
 76     m=strlen(s);
 77     
 78     int p=-1;
 79     f[0]=p;
 80     for(int i=1;i<n;i++)
 81     {
 82         while(p!=-1 && a[p+1]!=a[i]) p=f[p];
 83         if(a[p+1]==a[i]) p++;
 84         f[i]=p;
 85     }
 86     
 87     for(int i=0;i<n;i++)
 88     for(int j=0;j<26;j++)
 89     {
 90         char c=revh(j);
 91         
 92         /*
 93         int p=i;
 94         while(p!=-1 && a[p+1]!=c) p=f[p];
 95         if(a[p+1]==c) p++;
 96         tran[i][j]=p;
 97         */
 98         
 99         if(a[i+1]==c) tran[i][j]=i+1;
100         else tran[i][j]=( f[i]==-1 ? ( a[0]==c ? 0 : -1 ) : tran[f[i]][j] );
101     }
102     
103     for(int i=0;i<m;i++) pre[i]=i-1;
104     state[-1]=-1;
105     int curp=-1;
106     for(int i=0;i<m;i++)
107     {
108         char c=s[i];
109         
110         if(curp!=-1)
111         curp=tran[curp][ch(c)];
112         else 
113         curp=( a[0]==c )-1;
114         
115         state[i]=curp;
116         
117         if(curp==n-1)
118         {
119             int p=i;
120             for(int j=0;j<n;j++)
121             {
122                 s[p]=0;
123                 p=pre[p];
124             }
125             curp=state[p];
126             pre[i+1]=p;
127         }
128     }
129     
130     for(int i=0;i<m;i++) if(s[i]) printf("%c",s[i]); printf("
");
131     
132     return 0;
133 }
View Code

拿了VJ上A掉的一道题去交结果TLE.......然后发现trans数组的递推的复杂度不对........

由于数据规模极高,要改trans.....WA了两发.......

递推求trans数组的时候注意对自动机的起点(编号-1)的处理.......

 

 


AC BZOJ 2434 NOI2011 阿狸的打字机

  1 #include <cstdio>
  2 #include <fstream>
  3 #include <iostream>
  4  
  5 #include <cstdlib>
  6 #include <cstring>
  7 #include <algorithm>
  8 #include <cmath>
  9  
 10 #include <queue>
 11 #include <vector>
 12 #include <map>
 13 #include <set>
 14 #include <stack>
 15 #include <list>
 16  
 17 typedef unsigned int uint;
 18 typedef long long int ll;
 19 typedef unsigned long long int ull;
 20 typedef double db;
 21  
 22 using namespace std;
 23  
 24 inline int getint()
 25 {
 26     int res=0;
 27     char c=getchar();
 28     bool mi=false;
 29     while(c<'0' || c>'9') mi=(c=='-'),c=getchar();
 30     while('0'<=c && c<='9') res=res*10+c-'0',c=getchar();
 31     return mi ? -res : res;
 32 }
 33 inline ll getll()
 34 {
 35     ll res=0;
 36     char c=getchar();
 37     bool mi=false;
 38     while(c<'0' || c>'9') mi=(c=='-'),c=getchar();
 39     while('0'<=c && c<='9') res=res*10+c-'0',c=getchar();
 40     return mi ? -res : res;
 41 }
 42 
 43 //==============================================================================
 44 //==============================================================================
 45 //==============================================================================
 46 //==============================================================================
 47 
 48 
 49 int s[105000][26];
 50 int pre[105000];
 51 int f[105000];
 52 int val[105000];
 53 int ncnt=2;
 54 
 55 int root=1;
 56 
 57 char a[105000];
 58 int p[105000],pcnt;
 59 
 60 int n,m;
 61 
 62 void BuildTrie()
 63 {
 64     int x=1;
 65     for(int i=0;i<n;i++)
 66     if(islower(a[i]))
 67     {
 68         int v=a[i]-'a';
 69         if(!s[x][v])
 70         {
 71             s[x][v]=ncnt;
 72             pre[ncnt]=x;
 73             val[ncnt]=v;
 74             ncnt++;
 75         }
 76         x=s[x][v];
 77     }
 78     else if(a[i]=='P')
 79         p[++pcnt]=x;
 80     else if(a[i]=='B')
 81         x=pre[x];
 82 }
 83 
 84 typedef pair<int,int> pl;
 85 queue<pl> q;
 86 void BuildAutomaton()
 87 {
 88     for(int i=0;i<26;i++)
 89     if(s[1][i])
 90     {
 91         f[s[1][i]]=1;
 92         for(int j=0;j<26;j++)
 93         if(s[s[1][i]][j])
 94         q.push(pl(s[s[1][i]][j],1));
 95     }
 96     
 97     while(!q.empty())
 98     {
 99         int x=q.front().first;
100         int p=q.front().second;
101         q.pop();
102         int v=val[x];
103         
104         while(p!=1 && !s[p][v]) p=f[p];
105         if(s[p][v]) p=s[p][v];
106         f[x]=p;
107         
108         for(int i=0;i<26;i++)
109         if(s[x][i]) q.push(pl(s[x][i],p));
110     }
111     
112 }
113 
114 struct query_link
115 {
116     int x;
117     int t;
118     int res;
119     query_link*nxt;
120 
121 }qpool[105000];
122 query_link*qds[105000];
123 bool cmp(const query_link&a,const query_link&b)
124 { return a.t<b.t; }
125 
126 struct edge
127 {
128     int in;
129     edge*nxt;
130 }pool[105000];
131 edge*et=pool;
132 edge*eds[105000];
133 void addedge(int a,int b)
134 { et->in=b; et->nxt=eds[a]; eds[a]=et++; }
135 #define FOREACH_EDGE(i,j) for(edge*i=eds[j];i;i=i->nxt)
136 
137 int loc[105000]; //points' location record.
138 int lci[105000]; //location's points record.
139 int tot[105000];
140 int lcnt=0;
141 
142 int SeqBuildDFS(int x)
143 {
144     lci[lcnt++]=x;
145     FOREACH_EDGE(e,x)
146     tot[x]+=SeqBuildDFS(e->in);
147     return tot[x]+=1;
148 }
149 
150 int t[105000];
151 void Change(int p,int v)
152 { p++; for(;p<=lcnt;p+=(p&-p)) t[p]+=v; }
153 int Query(int p)
154 { p++; int res=0; for(;p;p-=(p&-p)) res+=t[p]; return res; }
155 
156 void DFS(int x)
157 {
158     if(x!=1) Change(loc[x],1);
159     
160     for(query_link*q=qds[x];q;q=q->nxt)
161     q->res=Query(loc[q->x]+tot[q->x]-1)-Query(loc[q->x]-1);
162     
163     for(int i=0;i<26;i++)
164     if(s[x][i]) DFS(s[x][i]);
165     
166     if(x!=1) Change(loc[x],-1);
167 }
168 
169 
170 int main()
171 {
172     scanf("%s",&a);
173     n=strlen(a);
174     
175     BuildTrie();
176     BuildAutomaton();
177     
178     for(int i=2;i<ncnt;i++)
179     addedge(f[i],i);
180     
181     SeqBuildDFS(1);
182     
183     for(int i=0;i<lcnt;i++)
184     loc[lci[i]]=i;
185     
186     m=getint();
187     for(int i=0;i<m;i++)
188     {
189         int x=p[getint()];
190         int y=p[getint()];
191         qpool[i].x=x;
192         qpool[i].t=i;
193         qpool[i].nxt=qds[y];
194         qds[y]=&qpool[i];
195     }
196     
197     DFS(1);
198     
199     sort(qpool,qpool+m,cmp);
200     for(int i=0;i<m;i++) printf("%d
",qpool[i].res);
201     
202     return 0;
203 }
View Code

 DFS写的AC自动机TLE了,不造是自己写搓还是复杂度本来就不对..........

在AC自动机的Fail树上各种乱搞.........

要求一个字符串x的对另外一个字符串y的匹配个数.

考虑暴力,就是枚举y的前缀节点,如果一个前缀节点能跳跃到x的节点就把统计量+1.

建出Fail树以后....就是神奇的乱搞.....真的好神奇.....

我们想快速求出,对于每一个询问(x,y),在fail树上,y有多少个节点在x的子树下边.

我们把Trie树DFS一遍,维护当前路径上的所有点(DFS栈中的点)的存在信息.

具体来说,就是把Fail树的DFS序搞出来,每遍历到Trie树上一个节点就把这个节点在DFS序上的代表位置的值+1,离开就-1.这样区间查询一下就能很快求出某一个子树下有多少当前正在DFS栈中的点.....

头一次写DFS序.....DFS序要注意两点,一是代表区间的长度等于子树大小;

二是子树的根一定最先遍历到,所以在它的代表区间的最左边.

 


AC BZOJ 3172

  1 #include <cstdio>
  2 #include <fstream>
  3 #include <iostream>
  4  
  5 #include <cstdlib>
  6 #include <cstring>
  7 #include <algorithm>
  8 #include <cmath>
  9  
 10 #include <queue>
 11 #include <vector>
 12 #include <map>
 13 #include <set>
 14 #include <stack>
 15 #include <list>
 16  
 17 typedef unsigned int uint;
 18 typedef long long int ll;
 19 typedef unsigned long long int ull;
 20 typedef double db;
 21 typedef long double ldb;
 22  
 23 using namespace std;
 24  
 25 inline int getint()
 26 {
 27     int res=0;
 28     char c=getchar();
 29     while(c<'0' || c>'9') c=getchar();
 30     while('0'<=c && c<='9') res=res*10+c-'0',c=getchar();
 31     return res;
 32 }
 33 inline ll getll()
 34 {
 35     ll res=0;
 36     char c=getchar();
 37     bool mi=false;
 38     while(c<'0' || c>'9') mi=(c=='-'),c=getchar();
 39     while('0'<=c && c<='9') res=res*10+c-'0',c=getchar();
 40     return mi ? -res : res;
 41 }
 42 
 43 //==============================================================================
 44 //==============================================================================
 45 //==============================================================================
 46 //==============================================================================
 47 
 48 
 49 int s[1005000][26];
 50 int v[1005000];
 51 int c[1005000];
 52 int f[1005000];
 53 int ncnt=1;
 54 int Insert(char*a,int len)
 55 {
 56     int x=0;
 57     for(int i=0;i<len;i++)
 58     {
 59         int k=a[i]-'a';
 60         if(!s[x][k]) s[x][k]=ncnt++;
 61         x=s[x][k]; c[x]=k; v[x]++;
 62     }
 63     return x;
 64 }
 65 
 66 int q[1005000],qh,qt;
 67 int qr[1005000];
 68 void Build()
 69 {
 70     for(int i=0;i<26;i++)
 71     if(s[0][i])
 72     {
 73         f[s[0][i]]=0;
 74         for(int j=0;j<26;j++)
 75         if(s[s[0][i]][j])
 76         { qr[qt]=0; q[qt]=s[s[0][i]][j]; qt++; }
 77     }
 78     
 79     while(qh!=qt)
 80     {
 81         int x=q[qh];
 82         int p=qr[qh]; qh++;
 83         
 84         while(p && !s[p][c[x]]) p=f[p];
 85         if(s[p][c[x]]) p=s[p][c[x]];
 86         f[x]=p;
 87         
 88         for(int i=0;i<26;i++)
 89         if(s[x][i]) { q[qt]=s[x][i]; qr[qt]=p; qt++; }
 90     }
 91     
 92     //reversed BFS sequence is topological sorted.
 93     for(int i=qt-1;i>=0;i--) v[f[q[i]]]+=v[q[i]];
 94 }
 95 
 96 char st[100000];
 97 void DFS(int x,int dep)
 98 {
 99     if(x) st[dep]=c[x]+'a'; st[dep+1]=0;
100     printf("%d %s %d %c %d
",x,st,v[x],c[x]+'a',f[x]);
101     for(int i=0;i<26;i++) if(s[x][i]) DFS(s[x][i],dep+1);
102 }
103 
104 int n;
105 char inp[1005000];
106 int loc[1005000];
107 int main()
108 {
109     n=getint();
110     for(int i=0;i<n;i++)
111     {
112         scanf("%s",inp);
113         loc[i]=Insert(inp,strlen(inp));
114     }
115     
116     Build();
117     
118     for(int i=0;i<n;i++) printf("%d
",v[loc[i]]);
119     
120     return 0;
121 }
View Code

我的AC自动机代码向来比人家长一倍,抄了一下别人的代码结果狂WA不止....改成原始版本后就A了.....

这个题应该也可以用后缀数据结构做....

注意拓扑序不需要用拓扑排序求出来,BFS序的逆序满足拓扑关系.

...

 

原文地址:https://www.cnblogs.com/DragoonKiller/p/4328458.html