← 全部文章

CF547E Mike and Friends 题解

本文目录(3 节)
  1. 题意
  2. 题解
  3. 代码

CF547E Mike and Friends

题意

  • 给定 nn 个字符串 s1…ns_{1 \dots n}。
  • qq 次询问 sks_k 在 sl…rs_{l \dots r} 中出现了多少次。
  • n,∑∣s∣≤2×105n, \sum |s| \le 2 \times 10^5,q≤5×105q \le 5 \times 10^5。

题解

首先对 nn 个字符串建出 AC 自动机。

将询问离线并差分成两个询问。

将字符串顺着扫一遍,对扫过的字符串在 trie 上的所有节点贡献 +1+1。

假设此时扫到串 ii,那么在 ii 上的询问 sks_k 的贡献等于 sks_k 在 trie 上的终点在 fail 树上的子树贡献和。

按 fail 树的 dfs 序建树状数组维护即可,时间复杂度 O((n+q)log⁡n)\mathcal O((n + q) \log n)。

代码

const int N = 2e5 + 7, M = 26, Q = 5e5 + 7;
int n, m, q, p[N], trie[N][M], fail[N], f[N], t = 1, dfn[N], num, siz[N], c[N], k[Q], ans[Q];
char s[N];
vi e[N];

inline int ins(int n) {
	int p = 1;
	for (int i = 1; i <= n; i++) {
		int c = s[i] - 'a';
		if (!trie[p][c]) f[trie[p][c]=++t] = p;
		p = trie[p][c];
	}
	return p;
}

void dfs(int x) {
	dfn[x] = ++num, siz[x] = 1;
	for (ui i = 0; i < e[x].size(); i++) dfs(e[x][i]), siz[x] += siz[e[x][i]];
}

inline void build() {
	queue< int > q;
	for (int i = 0; i < M; i++)
		if (trie[1][i]) fail[trie[1][i]] = 1, q.push(trie[1][i]);
		else trie[1][i] = 1;
	while (q.size()) {
		int x = q.front();
		q.pop();
		for (int i = 0; i < M; i++)
			if (trie[x][i]) fail[trie[x][i]] = trie[fail[x]][i], q.push(trie[x][i]);
			else trie[x][i] = trie[fail[x]][i];
	}
	for (int i = 2; i <= t; i++) e[fail[i]].pb(i);
	dfs(1);
}

inline void add(int x) {
	while (x <= t) ++c[x], x += x & -x;
}

inline int ask(int x) {
	int ret = 0;
	while (x) ret += c[x], x -= x & -x;
	return ret;
}

int main() {
	rd(n), rd(q);
	for (int i = 1; i <= n; i++) rds(s, m), p[i] = ins(m);
	build();
	for (int i = 1; i <= n; i++) e[i].clear();
	for (int i = 1, l, r; i <= q; i++) {
		rd(l), rd(r), rd(k[i]);
		if (l > 1) e[l-1].pb(-i);
		e[r].pb(i);
	}
	for (int i = 1; i <= n; i++) {
		int x = p[i];
		while (x ^ 1) add(dfn[x]), x = f[x];
		for (ui j = 0; j < e[i].size(); j++) {
			int o = e[i][j] > 0 ? 1 : -1, t = abs(e[i][j]), x = p[k[t]];
			ans[t] += o * (ask(dfn[x] + siz[x] - 1) - ask(dfn[x] - 1));
		}
	}
	for (int i = 1; i <= q; i++) print(ans[i]);
	return 0;
}

标签:AC 自动机、前缀和/差分、树状数组

评论

    填写昵称即可留言。评论经站主审核后公开,请勿提交私人信息。

    正在连接评论服务…