AcWing 1063. 永无乡(并查集, 启发式合并,splay)

题目链接

解题思路

  题目相当于询问每个点所属集合的第\(k\)小的数的编号,查询某个数属于哪个集合可以用并查集来解决。题目还涉及了集合之间的合并,由于合并之后集合的元素会改变,所以需要动态询问第\(k\)小,可以用平衡树来解决。另外,在集合合并的时候需要用启发式合并,把小集合合并到大集合上,这样可以把时间复杂度降到\(nlog^2n\)的级别。

const int maxn = 1e5+10;
int n, m, a[maxn], p[maxn];
int find(int x) {
    return p[x]==x ? p[x]:p[x]=find(p[x]);
}
int rt[maxn], idx;
struct Node {
    int s[2], sz, v, p, num;
    void init(int _v, int _num, int _p) {
        v = _v, num = _num, p = _p;
        sz = 1;
    }
} tr[maxn*40];
inline void push_up(int u) {
    tr[u].sz = tr[tr[u].s[0]].sz+tr[tr[u].s[1]].sz+1;
}
void rotate(int x) {
    int y = tr[x].p, z = tr[y].p;
    int k = tr[y].s[1]==x;
    tr[z].s[tr[z].s[1]==y] = x, tr[x].p = z;
    tr[y].s[k] = tr[x].s[k^1], tr[tr[x].s[k^1]].p = y;
    tr[x].s[k^1] = y, tr[y].p = x;
    push_up(y), push_up(x);
}
void splay(int &rt,  int x, int k) {
    while(tr[x].p!=k) {
        int y = tr[x].p, z = tr[y].p;
        if (z!=k) 
            if ((tr[y].s[1]==x)^(tr[z].s[1]==y)) rotate(x);
            else rotate(y);
        rotate(x);
    }
    if (!k) rt = x;
}
void insert(int &rt, int v, int num) {
    int p = 0, u = rt;
    while(u) p = u, u = tr[u].s[v>tr[u].v];
    u = ++idx;
    if (p) tr[p].s[v>tr[p].v] = u;
    tr[u].init(v, num, p);
    splay(rt, u, 0);
}
void merge(int u, int &rt) {
    if (tr[u].v==INF || tr[u].v==-INF) return;
    insert(rt, tr[u].v, tr[u].num);
    if (tr[u].s[0]) merge(tr[u].s[0], rt);
    if (tr[u].s[1]) merge(tr[u].s[1], rt);
}
int query(int u, int k) {
    while(u) {
        int sz = tr[tr[u].s[0]].sz;
        if (sz>=k) u = tr[u].s[0];
        else if (sz+1==k) return tr[u].num;
        else k -= sz+1, u = tr[u].s[1];
    }
    return -1;
}
int main() {
    IOS;
    cin >> n >> m;
    for (int i = 1; i<=n; ++i) cin >> a[i];
    for (int i = 1; i<=n; ++i) p[i] = i;
    while(m--) {
        int a, b; cin >> a >> b;
        p[find(a)] = find(b);
    }
    for (int i = 1; i<=n; ++i) {
        int pi = find(i);
        if (!rt[pi]) {
            insert(rt[pi], -INF, i);
            insert(rt[pi], INF, i);
        }
        insert(rt[pi], a[i], i);
    }
    int q; cin >> q;
    while(q--) {
        char op[10]; int a, b;
        cin >> op >> a >> b;
        if (op[0]=='B') {
            int fa = find(a);
            int fb = find(b);
            if (fa!=fb) {
                if (tr[rt[fa]].sz<=tr[rt[fb]].sz) {
                    p[fa] = fb;
                    merge(rt[fa], rt[fb]);
                }
                else {
                    p[fb] = fa;
                    merge(rt[fb], rt[fa]);
                }
            }
        }
        else {
            int fa = find(a);
            if (tr[rt[fa]].sz-2<b) cout << -1 << endl;
            else cout << query(rt[fa], b+1) << endl;
        }
    }
    return 0;
}
posted @ 2021-08-02 10:18  shuitiangong  阅读(51)  评论(0编辑  收藏  举报