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;
    }
  • 相关阅读:
    GNU make manual 翻译(九十九)
    GNU make manual 翻译( 九十五)
    Shell的 for 循环小例子
    makefile中对目录遍历的小例子
    GNU make manual 翻译(九十三)
    GNU make manual 翻译( 一百)
    GNU make manual 翻译( 九十七)
    GNU make manual 翻译( 九十八)
    mapserver4.8.3 的readme.win32的中文翻译文件
    遥控器编程
  • 原文地址:https://www.cnblogs.com/CzYoL/p/7381469.html
Copyright © 2011-2022 走看看