AC自动机模板题
#include <iostream>
#include <string>
#include <cstring>
#include <queue>
using namespace std;
struct node{
int count; //记录以此为终点的单词的个数
node *fail;
node *son[26];
};
queue<node *>q;
node word[500010];
int e;
char str[1000005];
//创建一个新结点
node *newnode(){
word[++e].count = 0;
word[e].fail = NULL;
for (int i = 0; i < 26; i++)word[e].son[i] = NULL;
return &word[e];
}
void add(string s,node *root){
node *now = root;
int len = s.size();
for (int i = 0; i < len; i++){
int id = s[i] - 'a';
//如果该儿子节点不存在,新建一个结点
if (now->son[id] == NULL){
now->son[id] = newnode();
}
//如果该儿子结点是单词的结束位置,单词数量加1
if (i == len - 1)now->son[id]->count++;
now = now->son[id];
}
}
//用BFS的方法获得fail值
void ac_automation(node *root){
node *now = root;
//把根结点的fail设为NULL
now->fail = NULL;
q.push(now);
while (!q.empty()){
now = q.front();
q.pop();
//把now的26个儿子中不为空儿子的fail填充
for (int i = 0; i < 26; i++){
//如果是根的子节点,则fail指向root
if (now == root){
if (now->son[i] != NULL){
now->son[i]->fail = root;
q.push(now->son[i]);
}
}
//否则沿着fail向上搜索,直到找到一个结点,该节点的子节点id存在,则now->son[i]->fail 便指向该子节点
//若找不到符合要求的结点,则now->son[i]->fail 便指向root
else{
if (now->son[i] != NULL){
node *temp = now->fail;
while (temp != NULL){
if (temp->son[i] != NULL){
now->son[i]->fail = temp->son[i];
break;
}
temp = temp->fail;
}
if (temp == NULL)now->son[i]->fail = root;
q.push(now->son[i]);
}
}//end of else
}//end of for
}//end of while
}
int solve(char *s,node *root){
node *now = root;
int len = strlen(s), i = 0, ans = 0;
for (i = 0; i < len; i++){
int id = s[i] - 'a';
//如果id儿子不存在,则沿着fail找到存在id儿子的结点
while (now->son[id] == NULL&&now != root)now = now->fail;
//如果没找到,把就从root开始,否则就从id儿子开始
now = (now->son[id] == NULL) ? root : now->son[id];
node *temp = now;
while (temp != root){
ans += temp->count;
temp->count = 0;
temp = temp->fail;
}
}
return ans;
}
int main()
{
int t;
cin >> t;
while (t--){
int n;
cin >> n;
string s;
e = -1;
node *root = newnode();
for (int i = 0; i < n; i++){
cin >> s;
add(s,root);
}
scanf("%s", str);
ac_automation(root);
cout << solve(str, root) << endl;
}
}