[POI2000]病毒

如果存在一个环,且环上没有任何危险标记(即病毒代码段末尾一位的结点专门作的编号),此时 AC自动机 能一直在环上匹配,并且永远也不会得到为模式串的一个子串, 这个找环可以通过 dfs 来实现
在构造失配指针时,一个很明显的优化是:如果一个结点拥有了失配指针,它指向的结点如果有危险标记,自己必然也危险,因为它到根结点形成的串是自己到根节点的后缀。

#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 5;

int n, cnt;
int vis[N], ins[N];
string a[2005];
struct str {
	int end;
	int fail;
	int ch[2];
} AC[25000];

void build(string s) {
	int now = 0;
	for(int i = 0; i < s.size(); i++) {
		if(!AC[now].ch[s[i] - '0']) 
			AC[now].ch[s[i] - '0'] = ++cnt;
		now = AC[now].ch[s[i] - '0'];
	}
	AC[now].end = 1;
}
void Get_fail() {
	queue<int> q;
	int now = 1;
	for(int i = 0; i <= 1; i++) 
		if(AC[0].ch[i])
			AC[AC[0].ch[i]].fail = 0, q.push(AC[0].ch[i]);
	while(!q.empty()) {
		int u = q.front(); q.pop();
		for(int i = 0; i <= 1; i++) {
			if(AC[u].ch[i]) {
				AC[AC[u].ch[i]].fail = AC[AC[u].fail].ch[i];
				AC[AC[u].vis[i]].end |= AC[AC[AC[u].vis[i]].fail].end;
				q.push(AC[u].ch[i]);
			}
			else AC[u].ch[i] = AC[AC[u].fail].ch[i];
		}
	}
}
void dfs(int x) {
	if(ins[x]) {cout << "TAK
"; exit(0);}
	if(AC[x].end || vis[x])  return ;
	vis[x] = ins[x] = 1;
	dfs(AC[x].ch[0]);//注意这里不要判断(  if(AC[x].ch[0]) )因为一个安全的代码可以不在trie树上~~趴~~
	dfs(AC[x].ch[1]);
	ins[x] = 0;
}
int main() {
	cin >> n;
	for(int i = 1; i <= n; i++) {
		cin >> a[i];
		build(a[i]);
	}
	Get_fail(); dfs(0);
	cout << "NIE
";
	return 0;
}
原文地址:https://www.cnblogs.com/hyxss/p/13883382.html