【AC自动机/fail树】BZOJ3172- [Tjoi2013]单词
【题目大意】
http://www.lydsy.com:808/JudgeOnline/problem.php?id=3172
某人读论文,一篇论文是由许多单词组成。但他发现一个单词会在论文中出现很多次,现在想知道每个单词分别在论文中出现多少次。
【思路】
第一次写fail树。首先建立AC自动机,对于路径上的每一个点sum++,表示出现的次数。fail指针指向的后缀,如果从fail指针指向的点开始方向建立fail树,其子树的sum之和就等于以它作为后缀的串的总数,相当于它在文章中出现的个数。
*fail树好神奇啊,不过E数组到底应该开多大呢?struct类型的数组到底应该怎么计算空间呢?困惑。
【错误名】
AC自动机的fail指针建立错了…详细见注释。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<vector> 6 #include<queue> 7 #define Lnum 26 8 using namespace std; 9 const int MAXN=201; 10 const int MAXLEN=1000001; 11 int n; 12 int cnt=0; 13 struct ACauto 14 { 15 ACauto* next[Lnum]; 16 ACauto* fail; 17 int id,sum; 18 ACauto() 19 { 20 for (int i=0;i<Lnum;i++) next[i]=NULL; 21 fail=NULL; 22 sum=0; 23 id=++cnt; 24 } 25 }; 26 ACauto* rt=new ACauto(); 27 ACauto* node[MAXN]; 28 struct edge 29 { 30 ACauto* to; 31 edge* next; 32 edge() 33 { 34 to=NULL; 35 next=NULL; 36 } 37 }; 38 edge* E[MAXLEN*Lnum]; 39 40 void addedge(ACauto* u,ACauto* v) 41 { 42 edge* tmp=new edge; 43 tmp->to=v; 44 tmp->next=E[u->id]; 45 E[u->id]=tmp; 46 } 47 48 void insert(ACauto* rt,char* str,int order) 49 { 50 ACauto* tmp=rt; 51 int len=strlen(str); 52 for (int i=0;i<len;i++) 53 { 54 int index=str[i]-'a'; 55 if (tmp->next[index]==NULL) 56 tmp->next[index]=new ACauto(); 57 tmp=tmp->next[index]; 58 tmp->sum++; 59 } 60 node[order]=tmp; 61 } 62 63 void build(ACauto* rt) 64 { 65 queue<ACauto*> que; 66 que.push(rt); 67 while (!que.empty()) 68 { 69 ACauto* head=que.front();que.pop(); 70 for (int i=0;i<Lnum;i++) 71 { 72 if (head->next[i]!=NULL) 73 { 74 if (head==rt) 75 { 76 head->next[i]->fail=rt; 77 addedge(rt,head->next[i]); 78 } 79 else 80 { 81 ACauto* tmp=head->fail; 82 while (tmp!=NULL) 83 { 84 if (tmp->next[i]!=NULL) 85 { 86 head->next[i]->fail=tmp->next[i]; 87 //指向最长的后缀,所以是tmp->next[i],而不是tmp 88 addedge(tmp->next[i],head->next[i]); 89 break; 90 } 91 else tmp=tmp->fail; 92 } 93 if (tmp==NULL) 94 { 95 head->next[i]->fail=rt; 96 addedge(rt,head->next[i]); 97 } 98 } 99 que.push(head->next[i]); 100 } 101 } 102 } 103 } 104 105 void dfs(ACauto* rt) 106 { 107 for (edge* i=E[rt->id];i!=NULL;i=i->next) 108 { 109 dfs(i->to); 110 rt->sum+=i->to->sum; 111 } 112 } 113 114 void init() 115 { 116 scanf("%d",&n); 117 char str[MAXLEN]; 118 for (int i=0;i<n;i++) 119 { 120 scanf("%s",str); 121 insert(rt,str,i); 122 } 123 build(rt); 124 } 125 126 void getans() 127 { 128 dfs(rt); 129 for (int i=0;i<n;i++) cout<<node[i]->sum<<endl; 130 } 131 132 int main() 133 { 134 init(); 135 getans(); 136 return 0; 137 }