AC自动机

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;
}
posted @ 2019-11-25 22:23  天才美少女雪乃  阅读(169)  评论(0编辑  收藏  举报