[BZOJ3172][TJOI2013]单词 AC自动机

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3172

对这$n$个串建立AC自动机,求每个串的出现次数。

我们在建立时对每一个经过的节点sum++,然后在fail树上从叶子节点不断向上更新,因为父亲节点代表的是孩子节点的一个后缀,所以孩子出现过的父亲一定出现过,而fail指针的不遗漏性保证了答案不会丢失。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 int N,ch[1000010][26],fail[1000010],cnt=0;
 6 int sum[1000010],pos[1000010];
 7 char tmp[1000010];
 8 int Insert(char *s){
 9     int now=0;
10     for(int i=0;s[i];i++){
11         int idx=s[i]-'a';
12         if(!ch[now][idx]) ch[now][idx]=++cnt;
13         now=ch[now][idx];
14         sum[now]++;
15     }
16     return now;
17 }
18 int q[1000010];
19 void Setfail(){
20     q[1]=0;
21     int head=1,tail=1;
22     while(head<=tail){
23         int now=q[head];
24         for(int i=0;i<26;i++){
25             if(ch[now][i]){
26                 q[++tail]=ch[now][i];
27                 fail[ch[now][i]]=now?ch[fail[now]][i]:0;
28             }
29             else ch[now][i]=ch[fail[now]][i];
30         }
31         head++;
32     }
33     for(int i=tail;i>=1;i--) sum[fail[q[i]]]+=sum[q[i]];
34 }
35 int main(){
36     scanf("%d",&N);
37     for(int i=1;i<=N;i++){
38         scanf("%s",tmp);
39         pos[i]=Insert(tmp);
40     }
41     Setfail();
42     for(int i=1;i<=N;i++) printf("%d\n",sum[pos[i]]);
43     return 0;
44 }

 

posted @ 2017-10-07 21:23  halfrot  阅读(98)  评论(0编辑  收藏  举报