poj 2985 The k-th Largest Group (并查集x全局动态第k大)

题意:
。。。
思路:
用一个数据结构来存所有树的大小,合并操作先消去旧的再插入新的大小。
可以用 treap, BIT等等。。
这里有个树状数组 O(logn) 查询的方法,没能看懂。。

const int N = 200000 + 5;
typedef long long LL;

namespace Treap {
    static const int MaxNode = N;
    int root, nodes, key[MaxNode], fix[MaxNode],
    ch[MaxNode][2], cnt[MaxNode], siz[MaxNode];
    void init() {
        root = 0;
        nodes = 1;
        fix[0] = INT_MAX;
        siz[0] = 0;
    }

    inline void update(int x) {
        siz[x] = siz[ch[x][0]] + siz[ch[x][1]] + cnt[x];
    }

    void rot(int& x, int t) {
        int y = ch[x][t];
        ch[x][t] = ch[y][1^t];
        ch[y][1^t] = x;
        update(x);
        update(y);
        x = y;
    }

    void insert(int& x, int k) {
        if ( x ) {
            if ( key[x] == k ) {
                ++ cnt[x];
            } else {
                int t = key[x] < k;
                insert(ch[x][t], k);
                if ( fix[ch[x][t]] < fix[x]  ) {
                    rot(x, t);
                }
            }
        } else {
            x = nodes ++;
            key[x] = k;
            cnt[x] = 1;
            fix[x] = rand();
            ch[x][0] = ch[x][1] = 0;
        }
        update(x);
    }

    void erase(int& x, int k) {
        if ( key[x] == k ) {
            if ( cnt[x] > 1 ) {
                -- cnt[x];
            } else {
                if ( !ch[x][0] && !ch[x][1] ) {
                    x = 0;
                    return;
                } else {
                    int t = fix[ch[x][0]] > fix[ch[x][1]];
                    rot(x, t);
                    erase(ch[x][1^t], k);
                }
            }
        } else {
            int t = key[x] < k;
            if ( ch[x][t] ) erase(ch[x][t], k);
        }
        update(x);
    }

    int count(int x, int k) {
        if ( x ) {
            if ( key[x] == k )
                return cnt[x];
            else
                return count( ch[x][key[x] < k], k );
        } else
            return 0;
    }

    int getKth(int x, int k) {
        if ( k <= siz[ch[x][0]] )
            return getKth(ch[x][0], k);
        k -= siz[ch[x][0]] + cnt[x];
        if ( k <= 0 )
            return key[x];
        if ( k <= siz[ch[x][1]] )
            return getKth(ch[x][1], k);
        else
            throw runtime_error("this is no kth element");
    }
};


namespace UF {
    int pa[N], sz[N];

    int Find(int x) { return x == pa[x] ? x : pa[x] = Find(pa[x]); }

    void init(int n) {
        Treap::init();
        rep(i, 1, n) pa[i] = i, sz[i] = 1;
        rep(i, 1, n) Treap::insert(Treap::root, 1);
    }

    void Union(int x, int y) {
        int px = Find(x), py = Find(y);
        if ( px != py ) {
            Treap::erase(Treap::root, sz[px]);
            Treap::erase(Treap::root, sz[py]);
            sz[px] += sz[py];
            pa[py] = px;
            Treap::insert(Treap::root, sz[px]);
            #if 0
            cout << "after merge" << endl;
            int tot = tree.siz[tree.root];
            rep(i, 1, tot) cout << tree.getKth(tree.root, i) << ' '; cout << endl;
            #endif // 1
        }
    }

    int query(int k) {
        int tot = Treap::siz[Treap::root];
        try {
            return Treap::getKth(Treap::root, tot + 1 - k);
        } catch ( exception& e ) {
            return 1;
        }
        //return tree.getKth(tree.root, tot + 1 - k);
    }
}

int main() {
#ifdef _LOCA_ENV_
    freopen("input.in", "r", stdin);
#endif // _LOCA_ENV
    int n, m;
    scanf("%d%d", &n, &m);
    UF::init(n);
    int op, x, y;
    rep(i, 1, m) {
        scanf("%d", &op);
        if ( op == 0 ) {
            scanf("%d%d", &x, &y);
            //cout << "merge " << x << ' ' << y << endl;
            UF::Union(x, y);
        } else {
            scanf("%d", &x);
            //cout << "query " << x << endl;
            printf("%d\n", UF::query(x));
        }
    }
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值