P5357 【模板】AC自动机(二次加强版)

P5357 【模板】AC自动机(二次加强版)

该代码只有76分,一些样例超时

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 const int maxn = 2e6+5;
 4 struct word {
 5     int num;  // 出现次数
 6     int pos;  // 出现位置 
 7 }words[maxn];
 8 struct Aho_Corasock_Automaton {
 9     struct node {
10         int fail;  // 失配指针
11         int son[26];  // 子节点的位置
12         int end;  // 标记以该节点结尾的模式串的编号 
13     }Trie[maxn];
14     int cnt = 0; // Trie指针
15     void clear(int x) {  // 清空节点信息 
16         memset(Trie[x].son,0,sizeof(Trie[x].son));
17         Trie[x].fail = Trie[x].end = 0;
18     }
19     void insert(char *s, int num) {
20         int len = strlen(s);
21         int now = 0;  // Trie当前指针 
22         for (int i = 0; i < len; ++i) {
23             if (Trie[now].son[s[i]-'a'] == 0) { // 如果没有这个子节点 
24                 Trie[now].son[s[i]-'a'] = ++cnt;  // 构造该节点 
25                 clear(cnt);  // 清空新构造的节点里面的信息 
26             }
27             now = Trie[now].son[s[i]-'a']; 
28         }
29         if (Trie[now].end != 0) {  // 说明出现了相同的模式串 
30             words[num].pos = Trie[now].end;  // 将后面出现的模式串的位置更改为最先出现的相同模式串的位置 
31         }
32         else Trie[now].end = num;  // 标记以该节点结尾是哪个模式串 
33     }
34     void get_fail() {  // 构造fail指针 
35         queue<int> que;
36         for (int i = 0; i < 26; ++i) {  // 先提前构造第二层 
37             if (Trie[0].son[i] != 0) {  // 如果存在该节点 
38                 Trie[Trie[0].son[i]].fail = 0;  // fail指向root节点 
39                 que.push(Trie[0].son[i]);  // 加入队列 
40             }
41         }
42         while (!que.empty()) {  // bfs求fail指针 
43             int u = que.front(); que.pop();
44             for (int i = 0; i < 26; ++i) {
45                 if (Trie[u].son[i] != 0) {  // 如果存在该子节点 
46                     // 子节点的fail指针指向当前节点的fail指针指向内容相同的子节点 
47                     Trie[Trie[u].son[i]].fail = Trie[Trie[u].fail].son[i];
48                     que.push(Trie[u].son[i]);  // 加入队列 
49                 }
50                 else {  // 如果不存在这个子节点 
51                     // 当前节点的该子节点指向当前节点的fail指针指向的止隔子节点 
52                     Trie[u].son[i] = Trie[Trie[u].fail].son[i];
53                 }
54             }
55         }
56     }
57     void query(char *s) {
58         int len = strlen(s);
59         int now = 0, ans = 0;  // 当前Trie指针,答案ans
60         for (int i = 0; i < len; ++i) {
61             now = Trie[now].son[s[i]-'a'];
62             for (int t = now; t != 0; t = Trie[t].fail) {  // 暴力搜索 
63                 words[Trie[t].end].num++;  // 以该节点为结尾的模式串次数加一 
64             }
65         }
66     }
67 }AC;
68 char t[maxn], s[maxn];
69 int main() {
70     int n; scanf("%d",&n);
71     for (int i = 1; i <= n; ++i) {
72         scanf("%s",t);
73         words[i].pos = i;
74         words[i].num = 0;
75         AC.insert(t,i);        
76     }
77     AC.Trie[0].fail = 0;
78     AC.get_fail();
79     scanf("%s",s);
80     AC.query(s);
81     for (int i = 1; i <= n; ++i) {
82         printf("%d\n",words[words[i].pos].num);
83     }
84     return 0;
85 }

 

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 const int maxn = 2e6+5;
 4  
 5 struct Aho_Corasock_Automaton {
 6     struct node {
 7         int fail;  // 失配指针
 8         int son[26];  // 子节点的位置
 9         int in;  // 该节点的入度 
10         int ans;  // 出现次数 
11     }Trie[maxn];
12     int cnt = 0; // Trie指针
13     int ends[maxn];  // 记录该模式串是以哪个节点为结尾
14     void insert(char *s, int num) {
15         int len = strlen(s);
16         int now = 0;  // Trie当前指针 
17         for (int i = 0; i < len; ++i) {
18             if (Trie[now].son[s[i]-'a'] == 0) { // 如果没有这个子节点 
19                 Trie[now].son[s[i]-'a'] = ++cnt;  // 构造该节点 
20             }
21             now = Trie[now].son[s[i]-'a']; 
22         }
23         ends[num] = now;
24     }
25     void get_fail() {  // 构造fail指针 
26         queue<int> que;
27         for (int i = 0; i < 26; ++i) {  // 先提前构造第二层 
28             if (Trie[0].son[i] != 0) {  // 如果存在该节点 
29                 Trie[Trie[0].son[i]].fail = 0;  // fail指向root节点 
30                 que.push(Trie[0].son[i]);  // 加入队列 
31             }
32         }
33         while (!que.empty()) {  // bfs求fail指针 
34             int u = que.front(); que.pop();
35             for (int i = 0; i < 26; ++i) {
36                 if (Trie[u].son[i] != 0) {  // 如果存在该子节点 
37                     // 子节点的fail指针指向当前节点的fail指针指向内容相同的子节点 
38                     Trie[Trie[u].son[i]].fail = Trie[Trie[u].fail].son[i];
39                     que.push(Trie[u].son[i]);  // 加入队列 
40                 }
41                 else {  // 如果不存在这个子节点 
42                     // 当前节点的该子节点指向当前节点的fail指针指向的止隔子节点 
43                     Trie[u].son[i] = Trie[Trie[u].fail].son[i];
44                 }
45             }
46         }
47     }
48     void topu() {
49         queue<int> que;
50         for (int i = 1; i <= cnt; ++i) {
51             Trie[Trie[i].fail].in++; 
52         }
53         for (int i = 1; i <= cnt; ++i) {
54             if (Trie[i].in == 0) {
55                 que.push(i);  // 入度为0的加入队列 
56             }
57         }
58         while (!que.empty()) {
59             int u = que.front(); que.pop();
60             Trie[Trie[u].fail].ans += Trie[u].ans;
61             Trie[Trie[u].fail].in--;
62             if (Trie[Trie[u].fail].in == 0)
63                 que.push(Trie[u].fail); 
64         }
65     }
66     void query(char *s) {
67         int len = strlen(s);
68         int now = 0, ans = 0;  // 当前Trie指针,答案ans
69         for (int i = 0; i < len; ++i) {
70             now = Trie[now].son[s[i]-'a'];
71             Trie[now].ans++;  // 出现次数加一 
72         }
73     }
74 }AC;
75 char t[maxn], s[maxn];
76 int main() {
77     int n; scanf("%d",&n);
78     for (int i = 1; i <= n; ++i) {
79         scanf("%s",t);
80         AC.insert(t,i);        
81     }
82     AC.Trie[0].fail = 0;
83     AC.get_fail();
84     scanf("%s",s);
85     AC.query(s);
86     AC.topu();
87     for (int i = 1; i <= n; ++i) {
88         printf("%d\n",AC.Trie[AC.ends[i]].ans);
89     }
90     return 0;
91 }

 

posted @ 2019-10-21 13:08  麻辣猪仔  阅读(173)  评论(0)    收藏  举报