ac自动机

题目链接:

ac自动机的精华在于 (fail) 指针,
为了避免暴力跳 (fail) 指针使得复杂度爆炸,建出 (fail) 图就好了

P3808
https://www.luogu.com.cn/problem/P3808

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<queue>
using namespace std;
typedef long long ll;

const int maxn = 1000010; 

int n, rt = 0, tot = 0; 
ll ans = 0;
struct Node{
	int son[30], sz, fail;
}t[maxn];

char s[maxn];

void insert(){
	int p = rt;
	int len = strlen(s);
	for(int i = 0 ; i < len ; ++i){
		if(!t[p].son[s[i] - 'a']){
			t[p].son[s[i] - 'a'] = ++tot;
		}
		p = t[p].son[s[i] - 'a'];
	} 
	++t[p].sz;
}

queue<int> q; 
void build(){
	t[rt].fail = rt;
	for(int i = 0 ; i <= 25 ; ++i){
		if(t[rt].son[i]) q.push(t[rt].son[i]);
	}
	
	while(!q.empty()){
		int u = q.front(); q.pop();
		for(int i = 0 ; i <= 25 ; ++i){
			if(t[u].son[i]){
				t[t[u].son[i]].fail = t[t[u].fail].son[i];
				q.push(t[u].son[i]);
			} else{
				t[u].son[i] = t[t[u].fail].son[i];
			}
		}
	}
}

void query(){
	int p = rt;
	int len = strlen(s);
	for(int i = 0 ; i < len ; ++i){
		p = t[p].son[s[i] - 'a'];
		for(int j = p ; j && ~t[j].sz ; j = t[j].fail) ans += t[j].sz, t[j].sz = -1;
	}
}

ll read(){ ll s = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){ if(ch == '-') f = -1; ch = getchar(); } while(ch >= '0' && ch <= '9'){ s = s * 10 + ch - '0'; ch = getchar(); } return s * f; }

int main(){
	n = read();
	for(int i = 1 ; i <= n ; ++i){
		scanf("%s", s);
		insert();
	}
	
	build();
	
	scanf("%s", s);
	query();
	
	printf("%lld
", ans);
	
	return 0;
}

P3796
https://www.luogu.com.cn/problem/P3796

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<queue>
using namespace std;
typedef long long ll;

const int maxn = 20010; 

int n, rt = 0, tot = 0; 
int ans[maxn], c[maxn], mx;

struct Node{
	int son[30], en, fail;
}t[maxn];

char s[200][100];
char txt[1000010];

void insert(int num){
	int p = rt;
	int len = strlen(s[num]);
	for(int i = 0 ; i < len ; ++i){
		if(!t[p].son[s[num][i] - 'a']){
			t[p].son[s[num][i] - 'a'] = ++tot;
		}
		p = t[p].son[s[num][i] - 'a'];
	} 
	t[p].en = tot;
	c[num] = tot;
}

void build(){
	queue<int> q; 
	t[rt].fail = rt;
	for(int i = 0 ; i <= 25 ; ++i){
		if(t[rt].son[i]) q.push(t[rt].son[i]);
	}
	
	while(!q.empty()){
		int u = q.front(); q.pop();
		for(int i = 0 ; i <= 25 ; ++i){
			if(t[u].son[i]){
				t[t[u].son[i]].fail = t[t[u].fail].son[i];
				q.push(t[u].son[i]);
			} else{
				t[u].son[i] = t[t[u].fail].son[i];
			}
		}
	}
}

void query(){
	int p = rt;
	int len = strlen(txt);
	for(int i = 0 ; i < len ; ++i){
		p = t[p].son[txt[i] - 'a'];
		for(int j = p ; j ; j = t[j].fail) {
			++ans[t[j].en];
			if(t[j].en) mx = max(mx, ans[t[j].en]);
		}
	}
}

ll read(){ ll s = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){ if(ch == '-') f = -1; ch = getchar(); } while(ch >= '0' && ch <= '9'){ s = s * 10 + ch - '0'; ch = getchar(); } return s * f; }

int main(){
	while(1){
		memset(t, 0, sizeof(t));
		memset(ans, 0, sizeof(ans));
		memset(c, 0, sizeof(c));
		mx = 0; tot = 0;
		n = read();
		if(!n) break;
		for(int i = 1 ; i <= n ; ++i){
			scanf("%s", s[i]);
			insert(i);
		}
		
		build();
		
		scanf("%s", txt);
		query();
		
		printf("%d
", mx);
		for(int i = 1 ; i <= n ; ++i){
			if(ans[c[i]] == mx) printf("%s
", s[i]);
		}
	}

	return 0;
}

P5357 https://www.luogu.com.cn/problem/P5357
(fail) 树上差分

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<queue>
using namespace std;
typedef long long ll;

const int maxn = 200010;

int n, rt = 0, tot = 0; 
int ans[maxn], c[maxn], mx;

struct Node{
	int son[30], en, fail;
}t[maxn];

int h[maxn], cnt = 0;

struct E{
	int to, next;
}e[maxn << 1];

void add(int u, int v){
	e[++cnt].to = v;
	e[cnt].next = h[u];
	h[u] = cnt;
}

char s[2000010];
char txt[2000010];

void insert(int num){
	int p = rt;
	int len = strlen(s);
	for(int i = 0 ; i < len ; ++i){
		if(!t[p].son[s[i] - 'a']){
			t[p].son[s[i] - 'a'] = ++tot;
		}
		p = t[p].son[s[i] - 'a'];
	} 
	t[p].en = p;
	c[num] = p;
}

void build(){
	queue<int> q; 
	t[rt].fail = rt;
	for(int i = 0 ; i <= 25 ; ++i){
		if(t[rt].son[i]) {
			add(rt, t[rt].son[i]);
			q.push(t[rt].son[i]);
		}
	}
	
	while(!q.empty()){
		int u = q.front(); q.pop();
		for(int i = 0 ; i <= 25 ; ++i){
			if(t[u].son[i]){
				t[t[u].son[i]].fail = t[t[u].fail].son[i];
				add(t[u].son[i], t[t[u].son[i]].fail);
				add(t[t[u].son[i]].fail, t[u].son[i]);
				q.push(t[u].son[i]);
			} else{
				t[u].son[i] = t[t[u].fail].son[i];
			}
		}
	}
}

int d[maxn];

void query(){
	int p = rt;
	int len = strlen(txt);
	for(int i = 0 ; i < len ; ++i){
		p = t[p].son[txt[i] - 'a'];
		++d[p];
//		printf("%d ", p);
	}
}

void dfs(int u, int par){
//	printf("%d ", u);
	for(int i = h[u] ; i != -1 ; i = e[i].next){
		int v = e[i].to;
		if(v == par) continue; 
		dfs(v, u);
		d[u] += d[v];
	}
}

ll read(){ ll s = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){ if(ch == '-') f = -1; ch = getchar(); } while(ch >= '0' && ch <= '9'){ s = s * 10 + ch - '0'; ch = getchar(); } return s * f; }

int main(){
	while(scanf("%d", &n) != EOF){
		memset(h, -1, sizeof(h));
		memset(t, 0, sizeof(t));
		memset(ans, 0, sizeof(ans));
		memset(c, 0, sizeof(c));
		mx = 0; tot = 0;
		for(int i = 1 ; i <= n ; ++i){
			scanf("%s", s);
			insert(i);
		}
		
		build();
		
		scanf("%s", txt);
		query();
//		printf("
");
		
		dfs(0, 0);
//		printf("
");
		
		for(int i = 1 ; i <= n ; ++i){
			printf("%d
", d[c[i]]);
		}
	}

	return 0;
}
原文地址:https://www.cnblogs.com/tuchen/p/14189350.html