zoukankan      html  css  js  c++  java
  • HDU 1512 Monkey King(左偏树+并查集)

    【题目链接】 http://acm.hdu.edu.cn/showproblem.php?pid=1512

     

    【题目大意】

      现在有 一群互不认识的猴子,每个猴子有一个能力值,每次选择两个猴子,挑出他们所归属的部落中能力值最强的猴子打架,然后两个最强的猴子能力值减半,之后两个部落就合为一个部落,问每次合并后部落中最强的猴子能力值是多少

    【题解】

      要求每次取出一堆数字中最大的数字减半再放回去,显然这是优先队列可以完成的操作,但由于之后要将两堆数字合并,所以采用可并优先队列,考虑使用左偏树。在左偏树的维护中同时用并查集维护集合标记的更改,即可以满足题目中所有的要求。

    【代码】

    #include <cstdio>
    #include <algorithm> 
    using namespace std;
    const int N=100005;
    int n,m,f[N],x,y;
    struct Node{
        int l,r,d,v;
        Node(){}
        Node(int _l,int _r,int _d,int _v){l=_l,r=_r,d=_d,v=_v;}
    }T[N];
    int merge(int a,int b){
        if(!a)return b;if(!b)return a;
        if(T[a].v<T[b].v)swap(a,b);
        T[a].r=merge(T[a].r,b);
        f[T[a].r]=a;
        if(T[T[a].l].d<T[T[a].r].d)swap(T[a].l,T[a].r);
        T[a].d=T[a].r?T[T[a].r].d+1:0;
        return a;
    }
    int pop(int a){
        int l=T[a].l,r=T[a].r;
        f[T[a].l]=T[a].l;
        f[T[a].r]=T[a].r;
        T[a].l=T[a].r=T[a].d=0;
        return merge(l,r);
    }
    int sf(int x){return x==f[x]?x:f[x]=sf(f[x]);}
    int main(){
        while(~scanf("%d
    ",&n)){
            for(int i=1;i<=n;i++){
                scanf("%d",&x);
                T[i]=Node(0,0,0,x);
                f[i]=i;
            }scanf("%d",&m);
            while(m--){
                scanf("%d%d",&x,&y);
                x=sf(x),y=sf(y);
                if(x==y)puts("-1");
                else{
                    int tx=pop(x),ty=pop(y);
                    T[x].v/=2; x=merge(x,tx);
                    T[y].v/=2; y=merge(y,ty);
                    printf("%d
    ",T[merge(x,y)].v);
                }
            }
        }return 0;
    } 
  • 相关阅读:
    Markdown 简明语法手册
    linuxmint
    添加 Windows 8.1 无虚拟机启动项 解决极品飞车的不支持虚拟机报错
    工作室案例在线展示
    流风ASP.NET框架商业版-工作流1.0简介
    GNS3的使用2
    再见
    JSR303结合切面校验参数
    统一异常处理
    分布式会话
  • 原文地址:https://www.cnblogs.com/forever97/p/hdu1512.html
Copyright © 2011-2022 走看看