P5357 【模板】AC自动机(二次加强版)
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+7;
const int M=2e6+7;
char s[N],S[M];
int cnt,tot,to[N],ans[N],du[N];
struct node{
int fail,end,ch[27];
}t[N];
inline void insert(char *str){
int now=0;
int len=strlen(str);
for(int i=0;i<len;i++){
if(!t[now].ch[str[i]-'a'+1])
t[now].ch[str[i]-'a'+1]=++cnt;
now=t[now].ch[str[i]-'a'+1];//构造 trie 树
}
++tot;
if(t[now].end) to[tot]=t[now].end;
if(!t[now].end) t[now].end=tot;
}
queue <int> q;
int num[N];
void build(){
for(int i=1;i<=26;i++)
if(t[0].ch[i]){
t[t[0].ch[i]].fail=0;
q.push(t[0].ch[i]);
}
while(q.size()){//bfs 求出失配指针,指向的其实就是他的最大真后缀
int now=q.front();
q.pop();
for(int i=1;i<=26;i++){
if(t[now].ch[i]){
t[t[now].ch[i]].fail=t[t[now].fail].ch[i];
q.push(t[now].ch[i]);
du[t[t[now].ch[i]].fail]++;
}
else t[now].ch[i]=t[t[now].fail].ch[i];
}
}
}
void query(char *str){
int now=0;
int len=strlen(str);
for(int i=0;i<len;i++){
now=t[now].ch[str[i]-'a'+1];
num[now]++;
}
}
void topu(){
for(int i=1;i<=cnt;i++)//复杂度正确的 trie 树使用方式
if(!du[i]) q.push(i);
while(q.size()){
int now=q.front();
q.pop();
ans[t[now].end]=num[now];
num[t[now].fail]+=num[now];
if(!(--du[t[now].fail])) q.push(t[now].fail);
}
}
int main(){
int n;
cin>>n;
for(int i=1;i<=n;i++){
scanf("%s",s);
insert(s);
}
build();
scanf("%s",S);
query(S);
topu();
for(int i=1;i<=n;i++){
if(!to[i]) printf("%d\n",ans[i]);
else printf("%d\n",ans[to[i]]);
}
return 0;
}
P3966 [TJOI2013]单词
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+7;
char s[N];
int cnt,tot,to[N],num,du[N];
int sz[N],pos[N];
struct node{
int fail,end,ch[27];
}t[N];
inline void insert(char *str){
int now=0;
int len=strlen(str);
for(int i=0;i<len;i++){
if(!t[now].ch[str[i]-'a'+1])
t[now].ch[str[i]-'a'+1]=++cnt;
now=t[now].ch[str[i]-'a'+1];
sz[now]++;
}
++tot;//看对于AC自动机建出来的trie图的理解
pos[tot]=now;
}
queue <int> q;
void build(){
for(int i=1;i<=26;i++)
if(t[0].ch[i]){
t[t[0].ch[i]].fail=0;
q.push(t[0].ch[i]);
}
while(q.size()){
int now=q.front();
q.pop();
du[++num]=now;
for(int i=1;i<=26;i++){
if(t[now].ch[i]){
t[t[now].ch[i]].fail=t[t[now].fail].ch[i];
q.push(t[now].ch[i]);
}
else t[now].ch[i]=t[t[now].fail].ch[i];
}
}
}
int n;
void query(){
for(int i=cnt;i>=0;i--) sz[t[du[i]].fail]+=sz[du[i]];//这里按照bfs的顺序更新的,如果把A作为fail的点B有贡献的话,A作为B的最大后缀也一定有贡献,所以可以这样处理
for(int i=1;i<=n;i++) printf("%d\n",sz[pos[i]]);
}
int main(){
cin>>n;
for(int i=1;i<=n;i++){
scanf("%s",s);
insert(s);
}
build();
query();
return 0;
}