hdu5384(trie树)

hdu5384

给定n个字符串Ai

给定m个字符串Bi

问所有的Bi在每个Ai中出现了多少次

很显然,对Bi建Trie图,然后每次用Ai去匹配的时候,不断查找当前匹配串的最长后缀,这样就能找到答案了

比赛的时候也这样水过了。(又一次我认为这样不会过,但是交上去却过了)

如有有这样的数据的话

1

1 1

10^5个a

10^5个a

那么时间复杂度是10^10,

其实上面不断查找当前匹配串的最长后缀是没必要的,是重复操作的。

如果我们知道当前匹配串的最长后缀包含了多少个Bi,那么就不用去不断回溯了。

所以我们只要在构建fail指针的时候,处理处当前fail指针指向的字符串包含了多少个Bi,那么就不用不断的回溯了。

(哈哈,学到东西了)

  1 #include <stdio.h>
  2 #include <string.h>
  3 #include <stdlib.h>
  4 #include <algorithm>
  5 #include <iostream>
  6 #include <queue>
  7 #include <stack>
  8 #include <vector>
  9 #include <map>
 10 #include <set>
 11 #include <string>
 12 #include <math.h>
 13 using namespace std;
 14 #pragma warning(disable:4996)
 15 #pragma comment(linker, "/STACK:1024000000,1024000000")
 16 typedef long long LL;                   
 17 const int INF = 1<<30;
 18 /*
 19 
 20 */
 21 const int N = 1000000 + 10;
 22 struct Node
 23 {
 24     int fail, next[26];
 25     int cnt;
 26     void init()
 27     {
 28         fail = -1;
 29         cnt = 0;
 30         for (int i = 0; i < 26; ++i)
 31             next[i] = -1;
 32     }
 33 }Trie[N];
 34 int size;
 35 void insert(int root, char *str)
 36 {
 37     int idx, cur = root;
 38     for (int i = 0; str[i]; ++i)
 39     {
 40         idx = str[i] - 'a';
 41         if (Trie[cur].next[idx] == -1)
 42         {
 43             Trie[size].init();
 44             Trie[cur].next[idx] = size++;
 45         }
 46         cur = Trie[cur].next[idx];
 47     }
 48     Trie[cur].cnt++;
 49 }
 50 void makeFail(int root)
 51 {
 52     queue<int> q;
 53     for (int i = 0; i < 26; ++i)
 54     {
 55         if (Trie[root].next[i] == -1)
 56             Trie[root].next[i] = root;
 57         else
 58         {
 59             Trie[Trie[root].next[i]].fail = root;
 60             q.push(Trie[root].next[i]);
 61         }
 62     }
 63     while (!q.empty())
 64     {
 65         int cur = q.front();
 66         q.pop();
 67         for (int i = 0; i < 26; ++i)
 68         {
 69             if (Trie[cur].next[i] == -1)
 70             {
 71                 Trie[cur].next[i] = Trie[Trie[cur].fail].next[i];
 72             }
 73             else
 74             {
 75                 Trie[Trie[cur].next[i]].fail = Trie[Trie[cur].fail].next[i];
 76                 //处理处,当前fail指针指向的字符串包含了多少个Bi
 77                 Trie[Trie[cur].next[i]].cnt += Trie[Trie[Trie[cur].fail].next[i]].cnt;
 78                 q.push(Trie[cur].next[i]);
 79             }
 80 
 81         }
 82     }
 83 }
 84 int match(int root, char *str)
 85 {
 86     int i = 0;
 87     int idx;
 88     int cur = root;
 89     int ret = 0;
 90     while (str[i])
 91     {
 92         idx = str[i] - 'a';
 93         cur = Trie[cur].next[idx];
 94         //int tmp = cur;
 95         //while (tmp != root)
 96         //{
 97         //    ret += Trie[tmp].cnt;
 98         //    tmp = Trie[tmp].fail;
 99         //}
100         
101         ret += Trie[cur].cnt;
102         i++;
103     }
104     return ret;
105 }
106 /*
107 题目问所有的Bi在每一个Ai中出现的次数
108 
109 一个串的所有子串可以表示为它所有前缀的后缀
110 对所有的Bi建trie图
111 我们可以让每个Ai匹配的时候,就让这个当前字符串不断的去寻找最长后缀,
112 时间复杂度吵了
113 ,然而数据水,居然过了
114 */
115 
116 char str[666666];
117 char str2[666666];
118 int main()
119 {
120     int t, n, m;
121     //freopen("d:/in.txt", "r", stdin);
122     scanf("%d", &t);
123     while (t--)
124     {
125         scanf("%d%d", &n, &m);
126         int idx = 0;
127         size = 1;
128         Trie[0].init();
129         Trie[0].fail = 0;
130         for (int i = 0; i < n; ++i)
131         {
132             scanf("%s", str + idx);
133             idx += strlen(str + idx) + 1;
134         }
135         for (int i = 0; i < m; ++i)
136         {
137             scanf("%s", str2);
138             insert(0,str2);
139         }
140         makeFail(0);
141         idx = 0;
142         for (int i = 0; i < n; ++i)
143         {
144             printf("%d\n", match(0, str + idx));
145             idx += strlen(str + idx) + 1;
146         }
147     }
148     return 0;
149 }
View Code

 

posted @ 2015-08-13 22:19  justPassBy  阅读(266)  评论(0编辑  收藏  举报