BZOJ 3673 & 3674 可持久化并查集

用可持久化线段树维护并查集的fa数组
要按秩合并
好久不写,有点生疏。
修改时都要开新节点,这样才不会影响之前的版本

#include <bits/stdc++.h>
#define mid ((l + r) >> 1)
#define lp tree[p].l
#define rp tree[p].r

const int N = 2e5 + 7;

struct Node {
	int l, r;
};
int n;

struct Seg {
	Node tree[N * 50];
	int tol;
	void build(int &p, int l, int r) {
		if (!p) p = ++tol;
		if (l == r) {
			tree[p].l = l;
			tree[p].r = 1;
			return;
		}
		build(lp, l, mid);
		build(rp, mid + 1, r);
	}
	void update(int &p, int l, int r, int pos, Node v) {
		tree[++tol] = tree[p];
		p = tol;
		if (l == r) {
			tree[p] = v;
			return;
		}
		if (pos <= mid) update(lp, l, mid, pos, v);
		else update(rp, mid + 1, r, pos, v);
	}
	Node query(int p, int l, int r, int pos) {
		if (l == r) return tree[p];
		if (pos <= mid) return query(lp, l, mid, pos);
		return query(rp, mid + 1, r, pos);
	}
	Node find(int p, int x) {
		Node temp = query(p, 1, n, x);
		if (temp.l == x) return temp;
		return find(p, temp.l);
	}
} seg;

int root[N], m, ans;

int main() {
	scanf("%d%d", &n, &m);
	seg.build(root[0], 1, n);
	for (int opt, l, r, k, i = 1; i <= m; i++) {
		scanf("%d", &opt);
		root[i] = root[i - 1];
		if (opt == 1) {
			scanf("%d%d", &l, &r);
			l ^= ans, r ^= ans;
			Node fx = seg.find(root[i], l), fy = seg.find(root[i], r);
			if (fx.l == fy.l) continue;
			if (fx.r > fy.r) std::swap(fx, fy);
			seg.update(root[i], 1, n, fx.l, {fy.l, fx.r});
			seg.update(root[i], 1, n, fy.l, {fy.l, fx.r + fy.r});
		} else if (opt == 2) {
			scanf("%d", &k);
			k ^= ans;
			root[i] = root[k];
		} else {
			scanf("%d%d", &l, &r);
			l ^= ans, r ^= ans;
			Node fx = seg.find(root[i], l), fy = seg.find(root[i], r);
			ans = fx.l == fy.l;
			printf("%d\n", ans);
		}
	}
	return 0;
}
posted @ 2020-02-14 23:16  Mrzdtz220  阅读(87)  评论(0编辑  收藏  举报