BZOJ 2733: [HNOI2012]永无乡

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

#include 
using namespace std;

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

你可能感兴趣的:(BZOJ 2733: [HNOI2012]永无乡)