https://www.cnblogs.com/hyfhaha/p/10802604.html
易错点
多组数据初始化时,cnt要初始化为1,用完之后要对trie的son数组清0,其他可以不清0但是son必须清0,这个会影响拓扑和fail!
如果RE,一定是trie开小了,这样cnt++才会访问越界,而不是s,T之类的开小了
#include<cstdio>//https://www.cnblogs.com/hyfhaha/p/10802604.html
#include<iostream>
#include<queue>
#include<cstring>
const int maxn=2e6+10;
using namespace std;
char s[maxn],T[maxn];//s为模板串,T为主串
int n,cnt,vis[200051],in[maxn],Map[maxn];//n为模板串个数,cnt为树下标,vis存放答案(每个模板串出现的次数),in为入度,Map记录模板串编号
struct node {
int son[26],fail,flag,ans;//flag记录这是第几个模板串(模板串编号)
} trie[maxn];//字典树存储模板串
queue<int> q;
void insert(char* s,int num) {//插入单词 num记录这是第几个模板串
int u=1,len=strlen(s);
for(int i=0; i<len; ++i) {
int v=s[i]-'a';
if(!trie[u].son[v]) trie[u].son[v]=++cnt;
u=trie[u].son[v];
}
if(!trie[u].flag) trie[u].flag=num;
Map[num]=trie[u].flag;
}
void getFail() {
for(int i=0; i<26; i++) trie[0].son[i]=1;//0是虚点,所有儿子都是根节点1 为了防止bfs时根节点儿子fail指向自己
q.push(1);
while(!q.empty()) {//bfs
int u=q.front();//父节点 其的fail一定是求过的
q.pop();
int Fail=trie[u].fail;//父节点的fail指向的节点
for(int i=0; i<26; i++) {
int v=trie[u].son[i];//子节点 下面求他的fail
if(!v) {//如果子节点不存在
trie[u].son[i]=trie[Fail].son[i];
continue;
}
trie[v].fail=trie[Fail].son[i];
in[trie[v].fail]++;
q.push(v);
}
}
}
void topu() {//拓扑更新fail的ans
for(int i=1; i<=cnt; ++i)
if(in[i]==0) q.push(i); //将入度为0的点全部压入队列里 如果入度为0,说明没有它不是别的节点的fail,那么就不需要被更新了
while(!q.empty()) {
int u=q.front(); //队首的ans是已经更新过的,用队首更新子节点
q.pop();
vis[trie[u].flag]=trie[u].ans; //如果有flag标记就更新vis数组 flag是模板串编号
int v=trie[u].fail; //v是u的fail连接的边 u->v
in[v]--; //将唯一连出去的出边fail的入度减去(拓扑排序的操作)
trie[v].ans+=trie[u].ans; //更新fail的ans值
if(in[v]==0) q.push(v); //拓扑排序常规操作
}
}
void query(char* s) {
int u=1,len=strlen(s);
for(int i=0; i<len; ++i)
u=trie[u].son[s[i]-'a'],trie[u].ans++;
}
//以下为模板移植易错点:多组数据初始化时,cnt要初始化为1,用完之后要对trie的son数组清0,其他可以不清0但是son必须清0,这个会影响拓扑和fail!
/*void init() {
for(int i=0;i<=cnt;i++){
trie[i].ans=trie[i].fail=trie[i].flag=0;
for(int j=0;j<26;j++){
trie[i].son[j]=0;
}
}
memset(vis,0,sizeof vis);
memset(in,0,sizeof in);
memset(Map,0,sizeof Map);
memset(flag,0,sizeof flag);
}*/
int main() {
scanf("%d",&n);
cnt=1;//易错点!如果不写这句话程序是错的
for(int i=1; i<=n; ++i) {
scanf("%s",s);
insert(s,i);
}
getFail();
scanf("%s",T);
query(T);
topu();
for(int i=1; i<=n; i++) printf("%d\n",vis[Map[i]]);
}