AC自动机模板题,用队列搞定。
需要注意的是单词有可能会重复!
#include"cstdlib"
#include"cstdio"
#include"cstring"
#include"cmath"
#include"queue"
#include"algorithm"
#include"iostream"
using namespace std;
char a[1000002]; //要查找的文章
struct trie
{
int mark; //标记单词
trie *next[27]; //子节点指针
trie *fail; //失配指针
trie()
{
mark=0;
fail=NULL;
memset(next,0,sizeof(next));
}
}*root;
void init(char *v) //建字典树就不说了
{
int i;
trie *p=root;
for(i=0;v[i];i++)
{
int tep=v[i]-'a';
if(p->next[tep]==NULL) p->next[tep]=new trie();
p=p->next[tep];
}
p->mark++;
}
void getac() //重点在这,构建失配指针
{
queue<trie*>q;
q.push(root);
while(!q.empty())
{
trie *p,*tep;
int i;
p=q.front();
q.pop();
for(i=0;i<26;i++)
{
if(p->next[i]!=NULL)
{
if(p==root) p->next[i]->fail=root; //如果当前是root,则他的子节点的失配指针必为root
else
{
tep=p->fail; //如果不是,从当前指针的失配指针开始寻找匹配
while(tep!=NULL)
{
if(tep->next[i]!=NULL) //找到
{
p->next[i]->fail=tep->next[i];
break;
}
tep=tep->fail; //逐个跳转失配指针寻找匹配
}
if(tep==NULL) p->next[i]->fail=root; //找不到则为root
}
q.push(p->next[i]);
}
}
}
}
int finde (char *a)
{
int i;
int ans=0;
trie *p=root,*q;
for(i=0;a[i];i++)
{
int tep=a[i]-'a';
while(p->next[tep]==NULL && p!=root) //逐个跳转, 知道找到或者回到root
p=p->fail;
p=p->next[tep];
if(p==NULL) p=root; //跳转为空 则还是为root
q=p;
while(q!=root && q->mark!=-1) //保持p不变,用q顺着失配指针寻找同kmp一样。
{
ans+=q->mark;
q->mark=-1;
q=q->fail;
}
}
return ans;
}
int main()
{
int t;
cin>>t;
while(t--)
{
int n;
scanf("%d",&n);
root=new trie();
while(n--)
{
char v[52];
scanf("%s",v);
init(v);
}
getac();
scanf("%s",a);
printf("%d\n",finde(a));
}
}