-
Notifications
You must be signed in to change notification settings - Fork 109
/
Copy pathDynamic Aho Corasick.cpp
154 lines (128 loc) · 4.03 KB
/
Dynamic Aho Corasick.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
#include <bits/stdtr1c++.h>
#define LOG 19
#define LET 26
#define MAX 300010
#define clr(ar) memset(ar, 0, sizeof(ar))
#define read() freopen("lol.txt", "r", stdin)
#define dbg(x) cout << #x << " = " << x << endl
using namespace std;
struct aho_corasick{
int id, edge[256];
vector <long long> counter;
vector <string> dictionary;
vector <map<char, int> > trie;
vector <int> leaf, fail, dp[LET];
inline int node(){
leaf.push_back(0);
counter.push_back(0);
trie.push_back(map<char, int>());
return id++;
}
inline int size(){
return dictionary.size();
}
void clear(){
trie.clear();
dictionary.clear();
fail.clear(), leaf.clear(), counter.clear();
for (int i = 0; i < LET; i++) dp[i].clear();
id = 0, node();
for (int i = 'a'; i <= 'z'; i++) edge[i] = i - 'a'; /// change here if different character set
}
aho_corasick(){
clear();
}
inline void insert(const char* str){
int j, x, cur = 0;
for (j = 0; str[j] != 0; j++){
x = edge[str[j]];
if (!trie[cur].count(x)){
int next_node = node();
trie[cur][x] = next_node;
}
cur = trie[cur][x];
}
leaf[cur]++;
dictionary.push_back(str);
}
inline void build(){ /// remember to call build
vector <pair<int, pair<int, int> > > Q;
fail.resize(id, 0);
Q.push_back({0, {0, 0}});
for (int i = 0; i < LET; i++) dp[i].resize(id, 0);
for (int i = 0; i < id; i++){
for (int j = 0; j < LET; j++){
dp[j][i] = i;
}
}
for(int i = 0; i < Q.size(); i++){
int u = Q[i].first;
int p = Q[i].second.first;
char c = Q[i].second.second;
for(auto& it: trie[u]) Q.push_back({it.second, {u, it.first}});
if (u){
int f = fail[p];
while (f && !trie[f].count(c)) f = fail[f];
if(!trie[f].count(c) || trie[f][c] == u) fail[u] = 0;
else fail[u] = trie[f][c];
counter[u] = leaf[u] + counter[fail[u]];
for (int j = 0; j < LET; j++){
if (u && !trie[u].count(j)) dp[j][u] = dp[j][fail[u]];
}
}
}
}
inline int next(int cur, char ch){
int x = edge[ch];
cur = dp[x][cur];
if (trie[cur].count(x)) cur = trie[cur][x];
return cur;
}
long long count(const char* str){ /// total number of occurrences of all words from dictionary in str
int cur = 0;
long long res = 0;
for (int j = 0; str[j] && id > 1; j++){ /// id > 1 because build will not be called if empty dictionary in dynamic aho corasick
cur = next(cur, str[j]);
res += counter[cur];
}
return res;
}
};
struct dynamic_aho{ /// dynamic aho corasick in N log N
aho_corasick ar[LOG];
dynamic_aho(){
for (int i = 0; i < LOG; i++) ar[i].clear();
}
inline void insert(const char* str){
int i, k = 0;
for (k = 0; k < LOG && ar[k].size(); k++){}
ar[k].insert(str);
for (i = 0; i < k; i++){
for (auto s: ar[i].dictionary){
ar[k].insert(s.c_str());
}
ar[i].clear();
}
ar[k].build();
}
long long count(const char* str){
long long res = 0;
for (int i = 0; i < LOG; i++) res += ar[i].count(str);
return res;
}
};
char str[MAX];
int main(){
dynamic_aho ar[2];
int t, i, j, k, l, flag;
scanf("%d", &t);
while (t--){
scanf("%d %s", &flag, str);
if (flag == 3){
printf("%lld\n", ar[0].count(str) - ar[1].count(str));
fflush(stdout);
}
else ar[flag - 1].insert(str);
}
return 0;
}