【模板】AC自动机

忘了博客地址了。
后续可能上升为总结。
代码比较复杂,细节很多,建议背下来。

【模板】AC自动机(简单版)
由势能分析可知,Query 部分时间复杂度是 O ( 2 ∗ l e n T ) O(2*lenT) O(2lenT)
统计 f a i l fail fail 答案部分是长度和,因为只统计是否出现。

#include<bits/stdc++.h>
using namespace std;
const int MAXC=26;
const int N=1e6+5;
struct node{
	int cnt,fail,nxt[MAXC];
}t[N];
int root,tot=1,res=0,T,n;
queue<int> Q;
char article[N],word[N];
void insert(char *s) {
	int len=strlen(s),r=1;
	for(int i=0;i<len;i++) {
		if(!t[r].nxt[s[i]-'a']) t[r].nxt[s[i]-'a']=++tot;
		r=t[r].nxt[s[i]-'a'];
	}
	t[r].cnt++;
}
void build() {//AcMachine
    t[1].fail=1;
	Q.push(1);
	while(Q.size()) {//order in depth
		int r=Q.front();Q.pop();
		for(int i=0;i<MAXC;i++) {
			int ch=t[r].nxt[i],p;
			if(ch) {
				Q.push(ch);
				for(p=t[r].fail;p!=1&&t[p].nxt[i]==0;p=t[p].fail);
				int tmp=t[p].nxt[i];
				if(tmp&&tmp!=ch) t[ch].fail=tmp;
				else t[ch].fail=1;
			}
		}
	}
}
void Query(char *s) {
	int r=1,len=strlen(s);
	for(int i=0;i<len;i++) {
		int p;
		for(p=r;p!=1&&t[p].nxt[s[i]-'a']==0;p=t[p].fail);
		r=t[p].nxt[s[i]-'a'];
		if(r==0) r=1;
		for(int temp=r;temp!=1;temp=t[temp].fail) {
			if(t[temp].cnt==-1) break;
			res+=t[temp].cnt;
			t[temp].cnt=-1;
		}
	}
}
int main() {
//	freopen("1.in","r",stdin);
	scanf("%d",&n);
	for(int i=1;i<=n;i++) {
		scanf("%s",word);
		insert(word);
	}
//	printf("yes");
	
	scanf("%s",article);
	build();
//	for(int i=1;i<=tot;i++) printf("fail[%d]=%d\n",i,t[i].fail);
	Query(article);
	printf("%d",res);
}

【模板】AC自动机(二次加强版)
区别只在于加了一个 t o p o topo topo 排序。

#include<bits/stdc++.h>
using namespace std; 
const int MAXC=26;
const int N=2e6+5;
struct node{
	int cnt,end,fail,nxt[MAXC];
}t[N];
int root,tot=1,res=0,T,n,ans[N];
int c[N];
int in[N];
queue<int> Q;
char article[N],word[N];
int insert(char *s) {
	int len=strlen(s),r=1;
	for(int i=0;i<len;i++) {
		if(!t[r].nxt[s[i]-'a']) t[r].nxt[s[i]-'a']=++tot;
		r=t[r].nxt[s[i]-'a'];
	}
	t[r].end=1;
	return r;
}
void build() {//AcMachine
    t[1].fail=1;
	Q.push(1);
	while(Q.size()) {//order in depth
		int r=Q.front();Q.pop();
		for(int i=0;i<MAXC;i++) {
			int ch=t[r].nxt[i],p;
			if(ch) {
				Q.push(ch);
				for(p=t[r].fail;p!=1&&t[p].nxt[i]==0;p=t[p].fail);
				int tmp=t[p].nxt[i];
				if(tmp&&tmp!=ch) t[ch].fail=tmp;
				else t[ch].fail=1;
			}
		}
	}
}
void Query(char *s) {
	int r=1,len=strlen(s);
	for(int i=0;i<len;i++) {
		int p;
		for(p=r;p!=1&&t[p].nxt[s[i]-'a']==0;p=t[p].fail);
		r=t[p].nxt[s[i]-'a'];
		if(r==0) r=1;
		t[r].cnt++;
//		for(int temp=r;temp!=1;temp=t[temp].fail) {
//			if(t[temp].cnt==-1) break;
//			res+=t[temp].cnt;
//			t[temp].cnt++;
//		}
	}
}
int main() {
//	freopen("1.in","r",stdin);
	scanf("%d",&n);
	for(int i=1;i<=n;i++) {
		scanf("%s",word);
		ans[i]=insert(word);
	}
//	printf("yes");
	
	scanf("%s",article);
	build();
//	for(int i=1;i<=tot;i++) printf("fail[%d]=%d\n",i,t[i].fail);
	Query(article);
	while(Q.size()) Q.pop();
	for(int i=1;i<=tot;i++) in[t[i].fail]++;
	for(int i=1;i<=tot;i++) if(!in[i]) Q.push(i);
	while(Q.size()) {
		int x=Q.front();Q.pop();
		t[t[x].fail].cnt+=t[x].cnt;
		if(--in[t[x].fail]==0) Q.push(t[x].fail);
	}
	for(int i=1;i<=n;i++) printf("%d\n",t[ans[i]].cnt);
}
posted @ 2020-12-12 17:10  仰望星空的蚂蚁  阅读(11)  评论(0)    收藏  举报  来源