struct AC_Automaton {
int next[maxn][26];
int fail[maxn];
int end[maxn];
int sz, root;
int newNode() {
for(int i = 0; i < 26; i++) {
next[sz][i] = -1;
}
fail[sz] = -1;
end[sz] = 0;
return sz++;
}
void init() {
sz = 0;
root = newNode();
}
void add(char s[]) {
int p = root, c;
for(int i = 0, len = strlen(s); i < len; i++) {
c = s[i] - 'a';
if(next[p][c] == -1) {
next[p][c] = newNode();
}
p = next[p][c];
}
++end[p];
}
void getFail() {
queue<int> q;
for(int i = 0; i < 26; i++) {
if(~next[root][i]) {
fail[next[root][i]] = root;
q.push(next[root][i]);
} else {
next[root][i] = root;
}
}
while(!q.empty()) {
int p = q.front();
q.pop();
for(int i = 0; i < 26; i++) {
if(~next[p][i]) {
fail[next[p][i]] = next[fail[p]][i];
q.push(next[p][i]);
} else {
next[p][i] = next[fail[p]][i];
}
}
}
}
// 多模式匹配
int solve(char s[]) {
int p = root, ans = 0;
for(int i = 0, len = strlen(s); i < len; i++) {
p = next[p][s[i] - 'a'];
for(int t = p; t && ~end[t]; t = fail[t]) {
ans += end[t];
end[t] = -1;
}
}
return ans;
}
} ac;
Q.E.D.