BZOJ4771: 七彩树

传送门
考虑维护每个颜色的虚树
按照 (dfn) 顺序维护这些点,在这些点上 (+1),相邻点的 (lca)(-1),这样,无论包含哪一个子树的几个点,子树权值和始终为 (1)
可以用 (set+LCA) 实现
现在变成了二维数点的问题,按照深度依次加入每个点用主席树维护,每个线段树维护 (dfs) 序即可

# include <bits/stdc++.h>
using namespace std;
typedef long long ll;

namespace IO {
	const int maxn(1 << 21 | 1);

	char ibuf[maxn], obuf[maxn], *iS, *iT, *oS = obuf, *oT = obuf + maxn - 1, c, st[66];
	int tp, f;

	inline char Getc() {
		return iS == iT ? (iT = (iS = ibuf) + fread(ibuf, 1, maxn, stdin), (iS == iT ? EOF : *iS++)) : *iS++;
	}

	template <class Int> inline void In(Int &x) {
		for (f = 1, c = Getc(); c < '0' || c > '9'; c = Getc()) f = c == '-' ? -1 : 1;
		for (x = 0; c >= '0' && c <= '9'; c = Getc()) x = (x << 1) + (x << 3) + (c ^ 48);
		x *= f;
	}

	inline void Flush() {
		fwrite(obuf, 1, oS - obuf, stdout);
		oS = obuf;
	}

	inline void Putc(char c) {
		*oS++ = c;
		if (oS == oT) Flush();
	}

	template <class Int> void Out(Int x) {
		if (!x) Putc('0');
		if (x < 0) Putc('-'), x = -x;
		while (x) st[++tp] = x % 10 + '0', x /= 10;
		while (tp) Putc(st[tp--]);
	}
}

using IO :: In;
using IO :: Out;
using IO :: Putc;
using IO :: Flush;

const int maxn(1e5 + 5);

int n, m, first[maxn], tot, rt[maxn], deep[maxn], col[maxn], ed[maxn];
int son[maxn], size[maxn], top[maxn], fa[maxn], nxt[maxn], dfn[maxn], mxd;
int ls[maxn * 80], rs[maxn * 80], sz[maxn * 80], idx, pos[maxn], id[maxn];
set <int> st[maxn];
set <int> :: iterator it, ot;

inline void Init() {
	int i;
	while (tot) ls[tot] = rs[tot] = sz[tot] = 0, --tot;
	memset(rt, 0, sizeof(rt)), memset(first, 0, sizeof(first));
	In(n), In(m), idx = mxd = 0;
	for (i = 1; i <= n; ++i) In(col[i]), id[i] = i, st[i].clear();
	for (i = 2; i <= n; ++i) In(fa[i]), nxt[i] = first[fa[i]], first[fa[i]] = i;
}

void Dfs1(int u) {
	int v;
	size[u] = 1, son[u] = 0, mxd = max(mxd, deep[u]);
	for (v = first[u]; v; v = nxt[v]) {
		deep[v] = deep[u] + 1, Dfs1(v);
		size[u] += size[v];
		son[u] = size[v] > size[son[u]] ? v : son[u];
	}
}

void Dfs2(int u, int tp) {
	int v;
	dfn[u] = ++idx, pos[idx] = u, top[u] = tp;
	if (son[u]) Dfs2(son[u], tp);
	for (v = first[u]; v; v = nxt[v]) if (v ^ son[u]) Dfs2(v, v);
	ed[u] = idx;
}

inline int Cmp(int x, int y) {
	return deep[x] < deep[y];
}

void Modify(int &x, int l, int r, int p, int v) {
	ls[++tot] = ls[x], rs[tot] = rs[x], sz[tot] = sz[x] + v, x = tot;
	if (l == r) return;
	int mid = (l + r) >> 1;
	p <= mid ? Modify(ls[x], l, mid, p, v) : Modify(rs[x], mid + 1, r, p, v);
}

int Query(int x, int y, int l, int r, int ql, int qr) {
	if (ql <= l && qr >= r) return sz[x] - sz[y];
	int mid = (l + r) >> 1, ret = 0;
	if (ql <= mid) ret = Query(ls[x], ls[y], l, mid, ql, qr);
	if (qr > mid) ret += Query(rs[x], rs[y], mid + 1, r, ql, qr);
	return ret;
}

inline int LCA(int x, int y) {
	assert(x && y);
	while (top[x] ^ top[y]) deep[top[x]] > deep[top[y]] ? x = fa[top[x]]: y = fa[top[y]];
	return deep[x] < deep[y] ? x : y;
}

inline void Prework() {
	int i, j, c, lst = 0, p;
	deep[1] = 1, Dfs1(1), Dfs2(1, 1), sort(id + 1, id + n + 1, Cmp);
	for (i = 1; i <= n; ++i) {
		c = col[p = id[i]];
		while (lst < deep[p]) rt[lst + 1] = rt[lst], ++lst;
		Modify(rt[lst], 1, n, dfn[p], 1);
		it = ot = st[c].insert(dfn[p]).first, ++ot;
		if (it != st[c].begin()) --it, Modify(rt[lst], 1, n, dfn[LCA(pos[*it], p)], -1), ++it;
		if (ot != st[c].end()) Modify(rt[lst], 1, n, dfn[LCA(pos[*ot], p)], -1);
		if (it != st[c].begin() && ot != st[c].end()) --it, Modify(rt[lst], 1, n, dfn[LCA(pos[*it], pos[*ot])], 1), ++it;
	}
}

inline void Solve() {
	int i, u, x, y, ans = 0;
	for (i = 1; i <= m; ++i) {
		In(u), In(y), u ^= ans, y ^= ans;
		x = deep[u], y = min(mxd, x + y);
		if (x > y) Putc('0'), ans = 0;
		else Out(ans = Query(rt[y], rt[x - 1], 1, n, dfn[u], ed[u]));
		Putc('
');
	}
}

int main() {
	int test;
	In(test);
	while (test) --test, Init(), Prework(), Solve();
	return Flush(), 0;
}
原文地址:https://www.cnblogs.com/cjoieryl/p/10275659.html