BZOJ 3881: [Coci2015]Divljak

首先建出 \(S\) 的AC自动机和fail树
要使T中每个字符串只被计算一次,那么就得在dfs序相邻的两个节点的lca处-1

#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 lowbit(i) ((i) & (-i))
#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 = 2e6 + 7;
int ch[N][26], fail[N], dep[N], in[N], out[N], root = 1, tol = 1, n, mp[N], dfn;
Edg
char s[N];
int fa[N], top[N], sz[N], son[N];

void ins(char *s, int index) {
	int len = strlen(s);
	int cur = root;
	rep (i, 0, len) {
		int c = s[i] - 'a';
		if (!ch[cur][c]) ch[cur][c] = ++tol;
		cur = ch[cur][c];
	}
	mp[index] = cur;
}
void build() {
	static int que[N];
	int l = 0, r = 0;
	rep (c, 0, 26) {
		if (!ch[root][c]) ch[root][c] = root;
		else que[r++] = ch[root][c], fail[ch[root][c]] = root;
	}
	while (l ^ r) {
		int cur = que[l++];
		rep (c, 0, 26) {
			if (!ch[cur][c]) ch[cur][c] = ch[fail[cur]][c];
			else que[r++] = ch[cur][c], fail[ch[cur][c]] = ch[fail[cur]][c];
		}
	}
	rep (i, root + 1, tol + 1) add(i, fail[i]);
}
void dfs(int u, int f = 0) {
	dep[u] = dep[f] + 1;
	in[u] = ++dfn;
	fa[u] = f;
	sz[u] = 1;
	es (u, i, v) {
		if (v == f) continue;
		dfs(v, u);
		sz[u] += sz[v];
		if (sz[v] > sz[son[u]]) son[u] = v;
	}
	out[u] = dfn;
}
void dfs2(int u, int tp) {
	top[u] = tp;
	if (!son[u]) return;
	dfs2(son[u], tp);
	es (u, i, v) if (v != fa[u] && v != son[u]) dfs2(v, v);
}
int Lca(int u, int v) {
	while (top[u] != top[v]) {
		if (dep[top[u]] < dep[top[v]]) std::swap(u, v);
		u = fa[top[u]];
	}
	return dep[u] < dep[v] ? u : v;
}
bool cmp(int a, int b) { return in[a] < in[b]; }
int tree[N];
void edit(int x, int v) { for (int i = x; i <= dfn; i += lowbit(i)) tree[i] += v; }
int query(int x) { int ans = 0; for (int i = x; i; i -= lowbit(i)) ans += tree[i]; return ans; }
void solve(char *s) {
	int len = strlen(s);
	static int st[N];
	int top = 0, cur = root;
	rep (i, 0, len) {
		cur = ch[cur][s[i] - 'a'];
		st[++top] = cur;
	}
	std::sort(st + 1, st + 1 + top, cmp);
	top = std::unique(st + 1, st + 1 + top) - st - 1;
	rep (i, 1, top + 1) {
		edit(in[st[i]], 1);
		if (i != top) edit(in[Lca(st[i], st[i + 1])], -1);
	}
}

int main() {
	scanf("%d", &n);
	rep (i, 1, n + 1) {
		scanf("%s", s);
		ins(s, i);
	}
	build();
	dfs(root);
	dfs2(root, root);
	int q;
	scanf("%d", &q);
	while (q--) {
		int opt;
		scanf("%d", &opt);
		if (opt == 1) {
			scanf("%s", s);
			solve(s);
		} else {
			int x;
			scanf("%d", &x);
			printf("%d\n", query(out[mp[x]]) - query(in[mp[x]] - 1));
		}
	}
	return 0;
}
posted @ 2020-02-28 14:26  Mrzdtz220  阅读(89)  评论(0编辑  收藏  举报