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

 

posted @ 2016-04-11 23:29  iiyiyi  阅读(237)  评论(0编辑  收藏  举报