https://www.luogu.org/problemnew/show/P3808
题目描述
给定n个模式串和1个文本串,求有多少个模式串在文本串里出现过。
输入输出格式
输入格式:
第一行一个n,表示模式串个数;
下面n行每行一个模式串;
下面一行一个文本串。
输出格式:
一个数表示答案
输入输出样例
输入样例#1: 输出样例#1:
2 2
a
aa
aa
#include <iostream>
#include <queue>
#define maxn 1000000
using namespace std;
struct tree//字典树
{
int fail;//失配指针
int vis[26];
int end;
}ac[maxn];
int cnt=0;
void build(string s)
{
int l=s.length();
int now=0;//当前指针
for(int i=0;i<l;i++)
{
if(ac[now].vis[s[i]-'a']==0)//trie没有这个节点
ac[now].vis[s[i]-'a']=++cnt;//构造
now=ac[now].vis[s[i]-'a'];//向下构造
}
ac[now].end++;
}
void getfail()
{
queue<int> q;
for(int i=0;i<26;i++)//对第二层预处理
{
if(ac[0].vis[i]!=0)
{
ac[ac[0].vis[i]].fail=0;
q.push(ac[0].vis[i]);
}
}
while(!q.empty())
{
int u=q.front();
q.pop();
for(int i=0;i<26;i++)
{
if(ac[u].vis[i]!=0)//存在节点
{
ac[ac[u].vis[i]].fail=ac[ac[u].fail].vis[i];//当前u节点的孩子节点的fail指针指向当前u节点的fail指针所指向的节点的相同子节点
q.push(ac[u].vis[i]);
}
else//不存在
ac[u].vis[i]=ac[ac[u].fail].vis[i];
}
}
}
int acquery(string s)
{
int l=s.length();
int now=0,ans=0;
for(int i=0;i<l;i++)
{
now=ac[now].vis[s[i]-'a'];
for(int t=now;t&&ac[t].end!=-1;t=ac[t].fail)
{
ans+=ac[t].end;
ac[t].end=-1;
}
}
return ans;
}
int main()
{
int n;
string s;
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>s;
build(s);
}
ac[0].fail=0;
getfail();
cin>>s;
cout<<acquery(s)<<endl;
return 0;
}
输入 her say she shr 绿色数字为每个节点的new值 蓝色数字为每个节点的cnt值 红线/蓝线为fail指针 (注:ac[3].end=1 ac[6].end=1 ac[8].end=1 ac[10].end=1
图为ac[].vis[]矩阵