zoukankan      html  css  js  c++  java
  • 【bzoj2733】永无乡(无旋treap启发式合并 + 并查集)

    传送门

    题目分析

      起初每个岛都是一个平衡树, 并查集的祖先都是自己。合并两岛时,pri较小的祖先会被作为合并后的祖先, 而两颗平衡树采用启发式合并。查询k值就是基本操作。

    code

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<string>
    #include<cmath>
    #include<algorithm>
    #include<vector>
    using namespace std;
    
    const int N = 1e5 + 5;
    int n, m;
    #define SZ(x) (x?x->sze:0)
    struct node{
        node *lc, *rc;
        int pri, sze, val, num;
        inline node* upt(){
            sze = SZ(lc) + SZ(rc) + 1;
            return this;
        }
    }pool[N], *tail = pool, *nod[N];
    int fa[N];
    
    inline int Rand(){
        static int RAND_VAL = 1388593021;
        return RAND_VAL += RAND_VAL << 2 | 1;
    }
    
    inline node* newNode(int v, int k){
        node *x = ++tail;
        x->sze = 1, x->val = v, x->pri = Rand(), x->num = k;
        return x;
    }
    
    inline node* Merge2(node *u, node *v){
        if(!u) return v;
        if(!v) return u;
        if(u->pri < v->pri){
            u->rc = Merge2(u->rc, v);
            return u->upt();
        }
        else{
            v->lc = Merge2(u, v->lc);
            return v->upt();
        }
    }
    
    inline int getAnc(int a){
        return fa[a] == a ? a : (fa[a] = getAnc(fa[a]));
    }
    
    inline void Split_v(node *u, int v, node *&x, node *&y){
        if(!u){
            x = y = NULL;
            return;
        }
        if(u->val <= v){
            Split_v(u->rc, v, x, y);
            u->rc = NULL, u->upt();
            x = Merge2(u, x);
        }
        else{
            Split_v(u->lc, v, x, y);
            u->lc = NULL, u->upt();
            y = Merge2(y, u);
        }
    }
    
    inline void Split_k(node *u, int k, node *&x, node *&y){
        if(!u){
            x = y = NULL;
            return;
        }
        if(SZ(u->lc) < k){
            Split_k(u->rc, k - SZ(u->lc) - 1, x, y);
            u->rc = NULL, u->upt();
            x = Merge2(u, x);
        }
        else{
            Split_k(u->lc, k, x, y);
            u->lc = NULL, u->upt();
            y = Merge2(y, u);
        }
    }
    
    inline node* Merge(node *u, node *v){
        if(!u) return v;
        if(!v) return u;
        node *L, *R;
        if(u->pri > v->pri) swap(u, v);
        Split_v(v, u->val, L, R);
        u->lc = Merge(u->lc, L);
        u->rc = Merge(u->rc, R);
        return u->upt();
    }
    
    inline int read(){
        int i = 0, f = 1; char ch = getchar();
        for(; (ch < '0' || ch > '9') && ch != '-';  ch = getchar());
        if(ch == '-') f = -1, ch = getchar();
        for(; ch >= '0' && ch <= '9'; ch = getchar())
            i = (i << 3) + (i << 1) + (ch - '0');
        return i * f;
    }
    
    inline void wr(int x){
        if(x < 0) putchar('-'), x = -x;
        if(x > 9) wr(x / 10);
        putchar(x % 10 + '0');
    }
    
    int main(){
        n = read(), m = read();
        for(int i = 1; i <= n; i++) fa[i] = i;
        for(int i = 1; i <= n; i++) nod[i] = newNode(read(), i);
        for(int i = 1; i <= m; i++){
            int a = read(), b = read();
            int fu = getAnc(a), fv = getAnc(b);
            if(fu != fv){
                if(nod[fu]->pri < nod[fv]->pri) fa[fv] = fu, nod[fu] = Merge(nod[fu], nod[fv]);
                else fa[fu] = fv, nod[fv] = Merge(nod[fu], nod[fv]);
            }
        }
    //    for(int i = 1; i <= n; i++) cout<<i<<":"<<nod[i]->sze<<endl;
        int Q = read();
        for(int i = 1; i <= Q; i++){
            char opt[5]; scanf("%s", opt);
            if(opt[0] == 'Q'){
                node *L, *R, *p, *q;
                int x = read(), k = read(), fx = getAnc(x);
    //            cout<<x<<" "<<k<<" "<<fx<<" "<<endl;
                Split_k(nod[fx], k - 1, L, R);
                Split_k(R, 1, p, q);
                if(p) wr(p->num);
                else wr(-1);
                putchar('
    ');
                nod[fx] = Merge2(L, Merge2(p, q));
            }
            else{
                int a = read(), b = read();
                int fu = getAnc(a), fv = getAnc(b);
                if(fu != fv){
                    if(nod[fu]->pri < nod[fv]->pri) fa[fv] = fu, nod[fu] = Merge(nod[fu], nod[fv]);
                    else fa[fu] = fv, nod[fv] = Merge(nod[fu], nod[fv]);
                }
            }
        }
        return 0;
    }
  • 相关阅读:
    Java实现 蓝桥杯VIP 基础练习 回形取数
    Java实现 蓝桥杯VIP 基础练习 回形取数
    Java实现 蓝桥杯VIP 基础练习 回形取数
    Java实现 蓝桥杯VIP 基础练习 回形取数
    Java实现 蓝桥杯VIP 基础练习 报时助手
    Java实现 蓝桥杯VIP 基础练习 报时助手
    Java实现 蓝桥杯VIP 基础练习 报时助手
    Java实现 蓝桥杯VIP 基础练习 报时助手
    Java实现 蓝桥杯VIP 基础练习 报时助手
    block的是发送信号的线程,又不是处理槽函数的线程
  • 原文地址:https://www.cnblogs.com/CzYoL/p/7381469.html
Copyright © 2011-2022 走看看