[模板]AC自动机

https://blog.csdn.net/creatorx/article/details/71100840
AC自动机就是一直跳fail边,然后找到整个要匹配的串就行了。
fail边:大概就是指向以当前节点表示的字符 为最后一个字符的 最长当前字符串的 后缀字符串的 最后一个节点(摘自上面的博客并断句
代码:luogu3808

#include <iostream>
#include <cstdio>
#include <queue>
#include <cstring>
using namespace std;
int n;
const int N=500010;
struct ACZDJ {
	int tr[N][26],fail[N],val[N],cnt;
	void insert(char *s) {
		int len=strlen(s),p=0;
		for(int i=0; i<len; i++) {
			if(!tr[p][s[i]-'a']) tr[p][s[i]-'a']=++cnt;
			p=tr[p][s[i]-'a'];
		}
		val[p]++;
	}
	void build() {
		queue<int>q;
		for(int i=0; i<26; i++)
			if(tr[0][i]) q.push(tr[0][i]),fail[tr[0][i]]=0;
		while(!q.empty()) {
			int u=q.front();
			q.pop();
			for(int i=0; i<26; i++) {
				if(tr[u][i]) q.push(tr[u][i]),fail[tr[u][i]]=tr[fail[u]][i];
				else tr[u][i]=tr[fail[u]][i];
			}
		}
	}
	int query(char *s) {
		int len=strlen(s),p=0,ans=0;
		for(int i=0; i<len; i++) {
			int v=s[i]-'a';
			p=tr[p][v];
			for(int j=p; ~val[j]&&j; j=fail[j]) {
				ans+=val[j];
				val[j]=-1;
			}
		}
		return ans;
	}
} AC;
char s[2000005];
int main() {
	scanf("%d",&n);
	while(n--) {
		scanf("%s",s);
		AC.insert(s);
	}
	AC.build();
	scanf("%s",s);
	cout<<AC.query(s);
}
posted @ 2018-07-15 21:07  SWHsz  阅读(120)  评论(0编辑  收藏  举报