AC自动机板子

$build$函数建立$ac$自动机以及$fail$树, $query$求出$ac$自动机中每个串在$s$中出现次数保存在$sz$数组中, 返回所有串出现总次数. 这个板子内存占用略大, 但是支持同时开多台ac自动机, 并且每台$ac$自动机都可以很容易清零.

const int N = 2e6+10;
int tot;
int ch[N][26], ch2[N][26];
int fail[N], val[N], sum[N], sz[N], End[N];
char s[N];
vector<int> g[N];
queue<int> q, Q;

struct AC_automaton {
	int T;
	void newnode(int &o) {
		if (Q.size()) {o = Q.front(); Q.pop();}
		else o=++tot;
		memset(ch[o],0,sizeof ch[o]);
		val[o] = sum[o] = sz[o] = 0;
	}
	void add(int &o, char *s, int v, int id) {
		if (!o) newnode(o);
		if (*s) add(ch[o][*s-'a'],s+1,v,id);
		else val[o] += v, End[id] = o;
	}
	void add(char *s, int v, int id) {
		add(T,s,v,id);
	}
	void build() {
		REP(i,0,25) ch2[T][i]=T;
		q.push(T), fail[T]=T;
		while (q.size()) {
			int x = q.front(); q.pop();
			sum[x] = sum[fail[x]]+val[x];
			REP(i,0,25) {
				if (ch[x][i]) {
					int y = ch[x][i];
					q.push(y);
					fail[y] = ch2[fail[x]][i];
					ch2[x][i] = y;
					g[fail[y]].pb(y);
				} else ch2[x][i] = ch2[fail[x]][i];
			}
		}
	}
	void dfs(int x) {
		for (int y:g[x]) dfs(y),sz[x]+=sz[y];
	}
	int query(char *s) {
		int n = strlen(s), now = T, ans = 0;
		REP(i,0,n-1) {
			now = ch2[now][s[i]-'a'];
			ans += sum[now], ++sz[now];
		}
		dfs(T);
		return ans;
	}
	void dfs2(int x) {
		for (int y:g[x]) dfs2(y);
		Q.push(x),g[x].clear();
	}
	void clear() {
		if (T) dfs2(T),T=0;
	}
} ac;
原文地址:https://www.cnblogs.com/uid001/p/10584412.html