• BZOJ 2733 [HNOI2012]永无乡(启发式合并+Treap+并查集)


    【题目链接】 http://www.lydsy.com/JudgeOnline/problem.php?id=2733

    【题目大意】

      给出n个点,每个点都有自己的重要度,现在有连边操作和查询操作,
      查询操作要求找出一个连通块中重要度第k的点的id

    【题解】

      我们用Treap维护每个连通块,对于连边操作,我们用启发式合并,
      将size比较小的Treap并入size比较大的Treap,同时用并查集维护连通信息

    【代码】

    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    using namespace std;
    const int N=100010,M=N;
    namespace Treap{
        struct node{
            int val,cnt,size,p,id;node *l,*r;
            node(){}
            node(int val,int id):val(val),id(id){p=rand();cnt=size=1;l=r=NULL;}
            void up(){size=cnt;if(l)size+=l->size;if(r)size+=r->size;}
        }*root[N],*pool[N];
        int top;
        node *new_node(){return pool[top++];}
        void Initialize(){top=0;for(int i=0;i<N;i++)pool[i]=new node();}
        void Rotatel(node*&x){node*y=x->r;x->r=y->l;x->up();y->l=x;y->up();x=y;}
        void Rotater(node*&x){node*y=x->l;x->l=y->r;x->up();y->r=x;y->up();x=y;}
        //往treap上插入点
        void Insert(node*&x,node y){
            if(!x){x=new_node();(*x)=y;return;}
            x->size++;
            if(y.val==x->val){x->cnt++;return;}
            if(y.val<x->val){
                Insert(x->l,y);
                if(x->l->p>x->p)Rotater(x);
            }else{
                Insert(x->r,y);
                if(x->r->p>x->p)Rotatel(x);
            }
        }
        // 查找第k小的元素
        int kth(node*x,int rnk){
            while(x){ 
                int d=x->l?x->l->size:0;
                if(rnk<=d)x=x->l;
                else if(rnk>d+x->cnt)rnk-=d+x->cnt,x=x->r;
                else return x->id;
            }return -1;
        }
        void Del_node(node*&u){pool[--top]=u;u=NULL;}
        // 将B树并入A树
        void merge(node*&A,node*&B){
            if(!B)return;
            if(B->l)merge(A,B->l);
            if(B->r)merge(A,B->r);
            Insert(A,*B); Del_node(B);
        }
    }
    int n,m,k,u,v,q; 
    namespace Union_Find_Set{  
        int f[M],size[M],block;
        void Initialize(){
            memset(f,0,sizeof(f));
            block=n;
        } 
        int Find(int x){
            if(!f[x])f[x]=x,size[x]=1;
            if(f[x]==x)return x;
            return f[x]=Find(f[x]);
        }
        void Union(int x,int y){
            x=Find(x); y=Find(y);
            if(x==y)return;
            if(size[x]>size[y])swap(x,y);
            f[x]=y; size[y]+=size[x];
            block--;
        }
    }
    void Heuristic_merge(int x,int y){
        int fx=Union_Find_Set::Find(x);
        int fy=Union_Find_Set::Find(y);
        if(fx==fy)return;
        if(Treap::root[fx]->size<Treap::root[fy]->size)swap(x,y),swap(fx,fy);
        Treap::merge(Treap::root[fx],Treap::root[fy]);
        Union_Find_Set::f[fy]=fx;
    }
    int main(){
        using namespace Treap;
    	Initialize();
    	Union_Find_Set::Initialize();
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++){
            scanf("%d",&k);
            Union_Find_Set::f[i]=i;
            Insert(root[i],node(k,i));
        }
        while(m--){
            scanf("%d%d",&u,&v);
            Heuristic_merge(u,v);
        }
        scanf("%d",&q);
        char op[5];
        while(q--){
            scanf("%s",op);
            if(op[0]=='B'){
                scanf("%d%d",&u,&v);
                Heuristic_merge(u,v);
            }else{
                scanf("%d%d",&u,&v);
                printf("%d
    ",kth(root[Union_Find_Set::Find(u)],v));
            }
        }return 0;
    }
  • 相关阅读:
    [转]直接拿来用!最火的Android开源项目(一)
    [原] jQuery EasyUI 1.3.2 离线API、Demo
    [原]通过GitHub Pages建立个人站点(详细步骤)
    [转]直接拿来用!最火的Android开源项目(二)
    堆排序
    单例模式
    【面试题】:火车运煤问题
    Aptana Studio 2.0 对JQuery的智能提示的支持
    vs2005 常用快捷键(备忘)
    关于ASP.NET在IIS上的一些问题的解决办法
  • 原文地址:https://www.cnblogs.com/forever97/p/bzoj2733.html
Copyright © 2020-2023  润新知