BZOJ 2434: [Noi2011]阿狸的打字机

首先建出AC自动机,只要记录一下节点的父节点即可
然后AC自动机字符串匹配的过程是先把字符串放进trie树里,把每个节点拿出来,然后再从每个节点沿着fail走
也就是如果一个字符串 \(s\) 出现在另一个字符串 \(t\) 中,那么在fail树上 \(s\)\(t\) 的祖先节点
离线询问,查询 \(x\)\(y\) 中出现了几次,就是当自动机上只有 \(y\) 到根节点每个节点有值时,\(x\) 在fail树上的子树和
转化为dfs序和树状数组查询区间和即可

#include <bits/stdc++.h>
#define pb push_back
#define fi first
#define se second
#define pii pair<ll, int>
#define lp p << 1
#define rp p << 1 | 1
#define mid ((l + r) >> 1)
#define ll long long
#define db double
#define rep(i,a,b) for(int i=a;i<b;i++)
#define per(i,a,b) for(int i=b-1;i>=a;i--)
#define Edg int ccnt=1,head[N],to[N*2],ne[N*2];void addd(int u,int v){to[++ccnt]=v;ne[ccnt]=head[u];head[u]=ccnt;}void add(int u,int v){addd(u,v);addd(v,u);}
#define Edgc int ccnt=1,head[N],to[N*2],ne[N*2],c[N*2];void addd(int u,int v,int w){to[++ccnt]=v;ne[ccnt]=head[u];c[ccnt]=w;head[u]=ccnt;}void add(int u,int v,int w){addd(u,v,w);addd(v,u,w);}
#define es(u,i,v) for(int i=head[u],v=to[i];i;i=ne[i],v=to[i])
const int MOD = 20170408;
void M(int &x) {if (x >= MOD)x -= MOD; if (x < 0)x += MOD;}
int qp(int a, int b = MOD - 2) {int ans = 1; for (; b; a = 1LL * a * a % MOD, b >>= 1)if (b & 1)ans = 1LL * ans * a % MOD; return ans % MOD;}
int gcd(int a, int b) { while (b) { a %= b; std::swap(a, b); } return a; }

const int N = 1e5 + 7;
int ch[N][26], fail[N], sz[N], tol = 1, root = 1, mp[N], n, fa[N];
Edg
char s[N];
int que[N];
void ins(char *s, int len) {
	int cur = root;
	rep (i, 0, len) {
		if (s[i] == 'B') cur = fa[cur];
		else if (s[i] == 'P') {
			mp[++n] = cur;
		} else {
			int c = s[i] - 'a';
			if (!ch[cur][c]) ch[cur][c] = ++tol;
			fa[ch[cur][c]] = cur; cur = ch[cur][c];
		}
	}
	int l = 0, r = 0; fail[root] = root;
	rep (i, 0, 26) {
		if (!ch[root][i]) ch[root][i] = root;
		else que[r++] = ch[root][i], fail[ch[root][i]] = root;
	}
	while (l != r) {
		int u = que[l++];
		rep (i, 0, 26) {
			if (!ch[u][i]) ch[u][i] = ch[fail[u]][i];
			else fail[ch[u][i]] = ch[fail[u]][i], que[r++] = ch[u][i];
		}
	}
	rep (i, root + 1, tol + 1) add(i, fail[i]);
}
int in[N], out[N], dfn;
void dfs(int u, int f = 0) {
	in[u] = ++dfn;
	es(u, i, v) {
		if (v == f) continue;
		dfs(v, u);
	}
	out[u] = dfn;
}

int ans[N], h[N], ft[N], nxt[N];
int tree[N];
inline int lowbit(int x) { return x & -x; }
inline void edit(int x, int v) {
	for (int i = x; i <= dfn; i += lowbit(i)) tree[i] += v;
}
inline int query(int x) {
	int ans = 0;
	for (int i = x; i; i -= lowbit(i)) ans += tree[i];
	return ans;
}
int main() {
	scanf("%s", s);
	int len = strlen(s);
	ins(s, len);
	dfs(root, 0);
	int m;
	scanf("%d", &m);
	rep (i, 1, m + 1) {
		int u, v;
		scanf("%d%d", &u, &v);
		ft[i] = u; nxt[i] = h[v]; h[v] = i;
	}
	int cur = root, n = 0;
	rep (i, 0, len) {
		if (s[i] == 'B') edit(in[cur], -1), cur = fa[cur];
		else if (s[i] == 'P') {
			++n;
			for (int id = h[n]; id; id = nxt[id])
				ans[id] = query(out[mp[ft[id]]]) - query(in[mp[ft[id]]] - 1);
		} else {
			int c = s[i] - 'a';
			fa[ch[cur][c]] = cur; cur = ch[cur][c];
			edit(in[cur], 1);
		}
	}
	rep (i, 1, m + 1) printf("%d\n", ans[i]);
	return 0;
}
posted @ 2020-02-28 14:22  Mrzdtz220  阅读(93)  评论(0编辑  收藏  举报