[NOI2011] 阿狸的打字机

\(\text{Solution}\)

对于一组 \(x,y\)
考虑 \(AC\) 自动机暴力运作的过程
就是在 \(Trie\) 上沿着 \(y\) 的路径走,每走到一处就暴力跳 \(fail\)
碰到一个 \(x\) 就产生 \(1\) 的贡献
\(y\) 到根的路径上的点,有多少个能一直跳 \(fail\) 碰到 \(x\)
\(fail\) 建成一棵树
那么碰到 \(x\) 就变成了 \(x\) 的子树中有这个点
这样不难想到离线,\(\text{dfs Trie}\) 树,把根到当前点的路径在 \(fail\) 树上打标记
询问就是问 \(fail\) 树中 \(x\) 的子树内有多少个点被打了标记
树状数组即可
(没想到一遍就过了

\(\text{Code}\)

#include <cstdio>
#include <cstring>
#define IN inline
using namespace std;

const int N = 1e5 + 5;
int n, ans[N], id[N], cnt, size;
char s[N];

int h[N], tot, hq[N], totq;
struct edge{int to, nxt, id;}e[N], Q[N];
IN void add(int x, int y) {e[++tot] = edge{y, h[x]}, h[x] = tot;}
IN void add(int x, int y, int id) {Q[++totq] = edge{y, hq[x], id}, hq[x] = totq;}

int dfn[N], dfc, siz[N];
void dfs_fail(int x) {
	dfn[x] = ++dfc, siz[x] = 1;
	for(int i = h[x], v; i; i = e[i].nxt) dfs_fail(v = e[i].to), siz[x] += siz[v];
}

struct BIT {
	int c[N];
	IN int lowbit(int x) {return x & -x;}
	IN void add(int x, int v) {for(; x <= dfc; x += lowbit(x)) c[x] += v;}
	IN int query(int x) {int s = 0; for(; x; x -= lowbit(x)) s += c[x]; return s;}
}T;

struct ACAM {
	int tr[N][26], fail[N], q[N], fa[N], now, nxt[N][26];
	IN ACAM() {now = 0;}
	
	IN void insert(char ch) {
		int c = ch - 'a';
		if (!tr[now][c]) tr[now][c] = ++size;
		fa[tr[now][c]] = now, now = tr[now][c];
	}
	IN void build() {
		for(int i = 0; i <= size; i++)
			for(int j = 0; j < 26; j++) nxt[i][j] = tr[i][j];
		
		int h = 0, t = 0, x;
		for(int i = 0; i < 26; i++) if (tr[0][i]) q[++t] = tr[0][i];
		while (h < t) {
			x = q[++h];
			for(int i = 0; i < 26; i++)
				if (tr[x][i]) fail[tr[x][i]] = tr[fail[x]][i], q[++t] = tr[x][i];
				else tr[x][i] = tr[fail[x]][i];
		}
		for(int i = 1; i <= size; i++) add(fail[i], i);
	}
	
	void dfs(int x) {
		T.add(dfn[x], 1);
		for(int i = hq[x], v; i; i = Q[i].nxt)
			ans[Q[i].id] = T.query(dfn[v = Q[i].to] + siz[v] - 1) - T.query(dfn[v] - 1);
		for(int i = 0; i < 26; i++)
			if (nxt[x][i]) dfs(nxt[x][i]);
		T.add(dfn[x], -1);
	}
}AC;

int main() {
	scanf("%s", s); int len = strlen(s), st = len;
	for(int i = 0; i < len; i++)
		if (s[i] != 'B' && s[i] != 'P') {st = i; break;}
	if (st < len) AC.insert(s[st]);
	for(int i = st + 1; i < len; i++)
		if (s[i] == 'P') id[++cnt] = AC.now;
		else if (s[i] == 'B') AC.now = AC.fa[AC.now];
		else AC.insert(s[i]);
	AC.build(), scanf("%d", &n);
	for(int i = 1, x, y; i <= n; i++) scanf("%d%d", &x, &y), add(id[y], id[x], i);
	dfs_fail(0), AC.dfs(0);
	for(int i = 1; i <= n; i++) printf("%d\n", ans[i]);
}
posted @ 2022-07-13 11:17  leiyuanze  阅读(24)  评论(0编辑  收藏  举报