[洛谷P3690]【模板】Link Cut Tree (动态树)

题目大意:给定$n$个点以及每个点的权值,要你处理接下来的$m$个操作。操作有$4$种。操作从$0到3编号。点从1到n编号。

  1. $0,x,y$:代表询问从$x$到$y$的路径上的点的权值的$xor$和。保证$x$到$y$是联通的。
  2. $1,x,y$:代表连接$x$到$y$,若$x$到$y$已经联通则无需连接。
  3. $2,x,y$:代表删除边$(x,y)$,不保证边$(x,y)$存在。
  4. $3,x,y$:代表将点$x$上的权值变成$y$。

题解:$LCT$

卡点:

 

C++ Code:

#include <cstdio>
#define maxn 300010
#define lc(rt) son[rt][0]
#define rc(rt) son[rt][1]
using namespace std;
int n, m;
int V[maxn], s[maxn];
int son[maxn][2], tg[maxn], fa[maxn];
inline void swap(int &a, int &b) {a ^= b ^= a ^= b;}
inline void swap(int rt) {swap(lc(rt), rc(rt));}
inline int get(int rt, int flag = 1) {return son[fa[rt]][flag] == rt;}
inline bool is_root(int rt) {return !(get(rt, 0) || get(rt));}
inline void pushdown(int rt) {
	swap(rt);
	tg[lc(rt)] ^= 1, tg[rc(rt)] ^= 1, tg[rt] ^= 1;
}
inline void update(int rt) {s[rt] = s[lc(rt)] ^ s[rc(rt)] ^ V[rt];}
inline void rotate(int x) {
	int y = fa[x], z = fa[y], b = get(x);
	if (!is_root(y)) son[z][get(y)] = x;
	fa[son[y][b] = son[x][!b]] = y; son[x][!b] = y;
	fa[y] = x; fa[x] = z;
	update(y); update(x);
}
int stack[maxn], top;
inline void splay(int x) {
	stack[top = 1] = x;
	for (int y = x; !is_root(y); stack[++top] = y = fa[y]);
	for (; top; top--) if (tg[stack[top]]) pushdown(stack[top]);
	for (; !is_root(x); rotate(x)) if (!is_root(fa[x])) 
		get(x) ^ get(fa[x]) ? rotate(x) : rotate(fa[x]);
	update(x);
}
inline void access(int rt) {for (int t = 0; rt; rc(rt) = t, t = rt, rt = fa[rt]) splay(rt);}
inline void make_root(int rt) {access(rt), splay(rt), tg[rt] ^= 1;}
inline void link(int x, int y) {make_root(x); fa[x] = y;}
inline void cut(int x, int y) {make_root(x); access(y); splay(y); fa[x] = lc(y) = 0;}
inline bool connect(int x, int y) {
	make_root(x); access(y); splay(y);
	return fa[x] == y;
}
inline bool uni(int x, int y) {
	make_root(x); access(y); splay(y);
	int tmp = x;
	while (tmp) tmp = fa[tmp];
	return tmp == y;
}
int main() {
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= n; i++) {
		scanf("%d", &V[i]);
		s[i] = V[i];
	}
	while (m --> 0) {
		int op, x, y;
		scanf("%d%d%d", &op, &x, &y);
		if (op == 0) {
			make_root(x); access(y); splay(y);
			printf("%d\n", s[y]);
		}
		if (op == 1) if (!uni(x, y)) link(x, y);
		if (op == 2) if (connect(x, y)) cut(x, y);
		if (op == 3) {
			access(x); splay(x);
			V[x] = y;
			update(x);
		}
	}
	return 0;
}

 

posted @ 2018-08-22 09:14  Memory_of_winter  阅读(196)  评论(0编辑  收藏  举报