CF163E e-Government

题目地址


题解

很明显那 (k) 个字符串作为模式串,建 AC 自动机。考虑每个字符串在当前动态维护的集合中出现多少次,由于总长度 $ le 10^6$,让匹配串在 AC 自动机上走,显然这个后缀出现的次数就是他在 fail 树上的子树的节点的 (cnt)

我们需要一个树上数据结构,动态维护:

  • 单点修改
  • 链求和

考虑维护每个点的练求和值,每个单点修改的影响是他子树的答案 (pm 1),所以问题转化为:

  • 子树修改
  • 单点求和

(dfs) 序 + 差分树状数组,搞定。

代码

#include <iostream>
#include <cstdio>
using namespace std;

const int N = 1e6 + 5;
typedef long long LL;

int m, n, match[N], tr[N][26], fail[N], idx;
int q[N], sz[N], c[N], dfn[N], cnt[N], dfncnt;
char s[N];

int head[N], numE = 0;
struct E{
	int next, v;
} e[N];

void add(int u, int v) {
	e[++numE] = (E) { head[u], v };
	head[u] = numE;
}

void insert(int id) {
	int p = 0;
	for (int i = 1; s[i]; i++) {
		int ch = s[i] - 'a';
		if (!tr[p][ch]) tr[p][ch] = ++idx;
		p = tr[p][ch];
	}
	match[id] = p;
}

void build() {
	int hh = 0, tt = -1;
	for (int i = 0; i < 26; i++)
		if (tr[0][i]) q[++tt] = tr[0][i];
	while (hh <= tt) {
		int u = q[hh++];
		for (int i = 0; i < 26; i++) {
			int v = tr[u][i];
			if (v) {
				fail[v] = tr[fail[u]][i];
				q[++tt] = v;
			} else tr[u][i] = tr[fail[u]][i];
		}
	}
	for (int i = 1; i <= idx; i++) add(fail[i], i);
}

void dfs(int u) {
	dfn[u] = ++dfncnt, sz[u] = 1;
	for (int i = head[u]; i; i = e[i].next) {
		int v = e[i].v;
		dfs(v);
		sz[u] += sz[v];
	}
}

void insert(int x, int k) {
	for (; x <= dfncnt; x += x & -x) c[x] += k;
}

int ask(int x) {
	int res = 0;
	for (; x; x -= x & -x) res += c[x];
	return res;
}

int main() {
	scanf("%d%d", &m, &n);
	for (int i = 1; i <= n; i++) {
		scanf("%s", s + 1);
		insert(i);
	}
	build();
	dfs(0);
	for (int i = 1; i <= n; i++) {
	    insert(dfn[match[i]], 1);
		insert(dfn[match[i]] + sz[match[i]], -1);
		cnt[i] = 1;
	}
	while (m--) {
		char op; cin >> op;
		if (op == '?') {
			scanf("%s", s + 1);
			int p = 0; LL ans = 0;
			for (int i = 1; s[i]; i++) {
				int ch = s[i] - 'a';
				p = tr[p][ch];
				ans += ask(dfn[p]);
			}
			printf("%lld
", ans);
		} else {
			int x; scanf("%d", &x);
			if ((op == '+' && cnt[x]) || (op == '-' && !cnt[x])) continue;
			cnt[x] = op == '+' ? 1 : 0;
			insert(dfn[match[x]], op == '+' ? 1 : -1);
			insert(dfn[match[x]] + sz[match[x]], op == '+' ? -1 : 1);
		} 
	}
	return 0;
}
原文地址:https://www.cnblogs.com/dmoransky/p/12442970.html