BZOJ 2733: [HNOI2012]永无乡

并查集加线段树合并
直接对两个集合的根合并,查询也在并查集的根上查,这样就不需要可持久化了

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

template<typename T>
inline void read(T &x) {
	x = 0; T f = 1; char ch = getchar();
	while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getchar(); }
	while (ch >= '0' && ch <= '9') { x = x * 10 + ch - 48; ch = getchar(); }
	x *= f;
}

const int N = 1e5 + 7;
int n, m, root[N], a[N], b[N];
int fa[N];
int getfa(int x) { return x == fa[x] ? x : fa[x] = getfa(fa[x]); }

struct Seg {
	struct Tree { int lp, rp, sum; } tree[N * 40];
	int cnt;
	inline void pushup(int p) {
		tree[p].sum = tree[tree[p].lp].sum + tree[tree[p].rp].sum;
	}
	void update(int &p, int l, int r, int pos) {
		if (!p) p = ++cnt;
		tree[p].sum = 0;
		if (l == r) { tree[p].sum = 1; return; }
		int mid = l + r >> 1;
		if (pos <= mid) update(tree[p].lp, l, mid, pos);
		else update(tree[p].rp, mid + 1, r, pos);
		pushup(p);
	}
	int query(int p, int l, int r, int k) {
		if (tree[p].sum < k) return -1;
		if (l == r) return b[l];
		int mid = l + r >> 1;
		if (tree[tree[p].lp].sum >= k) return query(tree[p].lp, l, mid, k);
		return query(tree[p].rp, mid + 1, r, k - tree[tree[p].lp].sum);
	}
	int merge(int u, int v, int l, int r) {
		if (!u || !v) return u + v;
		int mid = l + r >> 1;
		tree[u].lp = merge(tree[u].lp, tree[v].lp, l, mid);
		tree[u].rp = merge(tree[u].rp, tree[v].rp, mid + 1, r);
		pushup(u);
		return u;
	}
} seg;

int main() {
	read(n); read(m);
	for (int i = 1; i <= n; i++) {
		read(a[i]);
		fa[i] = i;
		b[a[i]] = i;
		seg.update(root[i], 1, n, a[i]);
	}
	while (m--) {
		int u, v;
		read(u), read(v);
		u = getfa(u);
		v = getfa(v);
		fa[v] = u;
		root[u] = seg.merge(root[u], root[v], 1, n);
	}
	int q;
	read(q);
	char s[3];
	while (q--) {
		scanf("%s", s);
		int u, v;
		read(u), read(v);
		if (s[0] == 'Q') {
			u = getfa(u);
			printf("%d\n", seg.query(root[u], 1, n, v));
		} else {
			u = getfa(u), v = getfa(v);
			fa[v] = u;
			root[u] = seg.merge(root[u], root[v], 1, n);
		}
	}
	return 0;
}
posted @ 2020-02-16 12:03  Mrzdtz220  阅读(64)  评论(0编辑  收藏  举报