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;
}