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;
    }
  • 相关阅读:
    一个简单的链表结构 分类: C/C++ 数据结构与算法 2015-06-14 16:39 129人阅读 评论(1) 收藏
    整数与浮点数的二进制表示方式 分类: C/C++ 2015-06-13 15:45 54人阅读 评论(0) 收藏
    对string的一些扩展函数 分类: C/C++ 2015-06-12 15:43 170人阅读 评论(1) 收藏
    SQL常用操作 2015-06-12 12:43 20人阅读 评论(0) 收藏
    Google C++编程风格 2015-06-11 11:25 36人阅读 评论(0) 收藏
    C++头文件编译问题 分类: C/C++ 2015-06-10 15:48 32人阅读 评论(0) 收藏
    服务器TIME_WAIT和CLOSE_WAIT详解和解决办法
    解决time_wait过多的问题
    Gdb调试多进程程序
    linux查看硬件配置命令
  • 原文地址:https://www.cnblogs.com/CzYoL/p/7381469.html
Copyright © 2011-2022 走看看