[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 }