uoj207 共价大爷游长沙 子树信息 LCT + 随机化 + 路径覆盖

题目传送门

http://uoj.ac/problem/207

题解

如果是一棵静态的树,有一个非常容易想到的算法:统计一下目前的每一个条边被几条路径经过,如果 \(x\)\(y\) 的边的这个值为 \(|S|\) 的话,那么就是合法的。

但是如果树是动态的,这个算法就有问题了。

link 和 cut 会导致一个点对之间的路径发生改变。


考虑到如果 \(x\)\(y\) 这条边必须要被经过的话,那么就是说覆盖了 \(x\)\(y\) 这条边的路径集恰好是 \(S\)

回顾 bzoj3569 DZY Loves Chinese II 的做法,把一条路径用同一个 \(int\) 范围内随机的值在路径上的边都异或一边,那么如果两条边的值相同就意味着两条边很有可能是被相同的路径集覆盖。

所以这题也同理,但是因为没有根,所以不能像一般的树一样做树上差分——所以我们直接求子树异或和就可以了。

所以可用维护子树信息的 LCT 维护。


时间复杂度 \(O(m\log n)\)

#include<bits/stdc++.h>

#define fec(i, x, y) (int i = head[x], y = g[i].to; i; i = g[i].ne, y = g[i].to)
#define dbg(...) fprintf(stderr, __VA_ARGS__)
#define File(x) freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout)
#define fi first
#define se second
#define pb push_back

template<typename A, typename B> inline char smax(A &a, const B &b) {return a < b ? a = b, 1 : 0;}
template<typename A, typename B> inline char smin(A &a, const B &b) {return b < a ? a = b, 1 : 0;}

typedef long long ll; typedef unsigned long long ull; typedef std::pair<int, int> pii;

template<typename I> inline void read(I &x) {
	int f = 0, c;
	while (!isdigit(c = getchar())) c == '-' ? f = 1 : 0;
	x = c & 15;
	while (isdigit(c = getchar())) x = (x << 1) + (x << 3) + (c & 15);
	f ? x = -x : 0;
}

const int N = 100000 + 7;
const int M = 300000 + 7;

#define lc c[0]
#define rc c[1]

int n, m, cnt, yz;
int b[M];
pii a[M];

struct Node { int c[2], rev, fa, v, xsum, xs; } t[N];
int st[N];
inline bool idtfy(int o) { return t[t[o].fa].rc == o; }
inline bool isroot(int o) { return t[t[o].fa].lc != o && t[t[o].fa].rc != o; }
inline void connect(int fa, int o, int d) { t[fa].c[d] = o, t[o].fa = fa; }
inline void pushup(int o) { t[o].xsum = t[t[o].lc].xsum ^ t[t[o].rc].xsum ^ t[o].xs ^ t[o].v; }
inline void pushdown(int o) {
	if (!t[o].rev) return;
	if (t[o].lc) t[t[o].lc].rev ^= 1, std::swap(t[t[o].lc].lc, t[t[o].lc].rc);
	if (t[o].rc) t[t[o].rc].rev ^= 1, std::swap(t[t[o].rc].lc, t[t[o].rc].rc);
	t[o].rev = 0;
}
inline void rotate(int o) {
	int fa = t[o].fa, pa = t[fa].fa, d1 = idtfy(o), d2 = idtfy(fa), b = t[o].c[d1 ^ 1];
	if (!isroot(fa)) t[pa].c[d2] = o; t[o].fa = pa;
	connect(o, fa, d1 ^ 1), connect(fa, b, d1);
	pushup(fa), pushup(o);
}
inline void splay(int o) {
	int x = o, tp = 0;
	st[++tp] = x;
	while (!isroot(x)) st[++tp] = x = t[x].fa;
	while (tp) pushdown(st[tp--]);
	while (!isroot(o)) {
		int fa = t[o].fa;
		if (isroot(fa)) rotate(o);
		else if (idtfy(o) == idtfy(fa)) rotate(fa), rotate(o);
		else rotate(o), rotate(o);
	}
}
inline void access(int o) {
	for (int x = 0; o; o = t[x = o].fa) {
		splay(o);
		t[o].xs ^= t[t[o].rc].xsum;
		t[o].rc = x;
		t[o].xs ^= t[t[o].rc].xsum;
		pushup(o);
	}
}
inline void mkrt(int o) {
	access(o), splay(o);
	t[o].rev ^= 1, std::swap(t[o].lc, t[o].rc);
}
inline int getrt(int o) {
	access(o), splay(o);
	while (pushdown(o), t[o].lc) o = t[o].lc;
	return splay(o), o;
}
inline void link(int x, int y) {
	mkrt(x);
	if (getrt(y) != x) access(y), splay(y), t[x].fa = y, t[y].xs ^= t[x].xsum, pushup(y);
}
inline void cut(int x, int y) {
	mkrt(x), access(y), splay(y);
	if (t[y].lc == x && !t[x].rc) t[y].lc = t[x].fa = 0, pushup(y);
}

inline void work() {
	while (m--) {
		int opt, x, y, u, v;
		read(opt);
		if (opt == 1) {
			read(x), read(y), read(u), read(v);
			cut(x, y), link(u, v);
		} else if (opt == 2) {
			read(x), read(y);
			v = rand(), yz ^= v;
			access(x), splay(x), t[x].v ^= v, pushup(x);
			access(y), splay(y), t[y].v ^= v, pushup(y);
			a[++cnt] = pii(x, y), b[cnt] = v;
		} else if (opt == 3) {
			read(u);
			x = a[u].fi, y = a[u].se, v = b[u], yz ^= v;
			access(x), splay(x), t[x].v ^= v, pushup(x);
			access(y), splay(y), t[y].v ^= v, pushup(y);
		} else if (opt == 4) {
			read(x), read(y);
			mkrt(x), access(y), splay(x);
			assert(t[x].rc == y && !t[y].lc);
//			dbg("t[y].xsum = %d, yz = %d, %d, %d\n", t[y].xsum, yz, t[y].v, t[y].xs);
			if (t[y].xsum != yz) puts("NO");
			else puts("YES");
		}
	}
}

inline void init() {
	srand(time(0) + (ull)new char);
	read(n), read(n), read(m);
	int x, y;
	for (int i = 1; i < n; ++i) read(x), read(y), link(x, y);
}

int main() {
#ifdef hzhkk
	freopen("hkk.in", "r", stdin);
#endif
	init();
	work();
	fclose(stdin), fclose(stdout);
	return 0;
}
posted @ 2019-10-24 18:02  hankeke  阅读(130)  评论(0编辑  收藏  举报