模板 Fail树

fail树就是将Trie图的Fail指针反指,从而生成一棵树,这个树的性质是:子节点对应字符串为以当前串为后缀,而子节点为原串的前缀,前缀的后缀就是嵌套在原串中的子串。

模板:BZOJ3172

Description

某人读论文,一篇论文是由许多单词组成。但他发现一个单词会在论文中出现很多次,现在想知道每个单词分别在论文中出现多少次。

Input

第一个一个整数N,表示有多少个单词,接下来N行每行一个单词。每个单词由小写字母组成,N<=200,单词长度不超过10^6

Output

输出N个整数,第i行的数字表示第i个单词在文章中出现了多少次。

Sample Input

3
a
aa
aaa

Sample Output

6
3
1
建完fail树统计子节点个数即可。
代码:
 1 #include<queue>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 struct trnt{
 6     int ch[26];
 7     int fl;
 8     int wgt;
 9     int hd;
10 }tr[2000000];
11 struct ent{
12     int twd;
13     int lst;
14 }e[1000000];
15 int fnd[1000];
16 char tmp[2000000];
17 int cnt;
18 int siz;
19 int n;
20 std::queue<int>Q;
21 void ade(int f,int t)
22 {
23     cnt++;
24     e[cnt].twd=t;
25     e[cnt].lst=tr[f].hd;
26     tr[f].hd=cnt;
27 }
28 void add(char *a,int x)
29 {
30     int root=0;
31     int len=strlen(a+1);
32     for(int i=1;i<=len;i++)
33     {
34         int c=a[i]-'a';
35         if(!tr[root].ch[c])
36             tr[root].ch[c]=++siz;
37         root=tr[root].ch[c];
38         tr[root].wgt++;
39     }
40     fnd[x]=root;
41     return ;
42 }
43 void Build()
44 {
45     int root=0;
46     for(int i=0;i<26;i++)
47         if(tr[root].ch[i])
48             Q.push(tr[root].ch[i]);
49     while(!Q.empty())
50     {
51         root=Q.front();
52         Q.pop();
53         for(int i=0;i<26;i++)
54         {
55             if(tr[root].ch[i])
56             {
57                 tr[tr[root].ch[i]].fl=tr[tr[root].fl].ch[i];
58                 Q.push(tr[root].ch[i]);
59             }else
60                 tr[root].ch[i]=tr[tr[root].fl].ch[i];
61         }
62     }
63     /*--------------------------以上是Trie图-------------------*/
64     
65     
66     
67     /*--------------------------以下为fail树-------------------*/ 
68     for(int i=1;i<=siz;i++)
69         ade(tr[i].fl,i); 
70     return ;
71 }
72 void dfs(int x)
73 {
74     for(int i=tr[x].hd;i;i=e[i].lst)
75     {
76         int to=e[i].twd;
77         dfs(to);
78         tr[x].wgt+=tr[to].wgt;
79     }
80 }
81 int main()
82 {
83     scanf("%d",&n);
84     for(int i=1;i<=n;i++)
85     {
86         scanf("%s",tmp+1);
87         add(tmp,i);
88     }
89     Build();
90     dfs(0);
91     for(int i=1;i<=n;i++)
92         printf("%d\n",tr[fnd[i]].wgt);
93     return 0;
94 }

 

转载于:https://www.cnblogs.com/blog-Dr-J/p/9672678.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值