• hdu1512 Monkey King(并查集,左偏堆)


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

    题目大意:有n个猴子,一开始每个猴子只认识自己。每个猴子有一个力量值,力量值越大表示这个猴子打架越厉害。如果2个猴子不认识,他们就会找他们认识的猴子中力量最大的出来单挑,单挑不论输赢,单挑的2个猴子力量值减半,这2拨猴子就都认识了,不打不相识嘛。现在给m组询问,如果2只猴子相互认识,输出-1,否则他们各自找自己认识的最牛叉的猴子单挑,求挑完后这拨猴子力量最大值。

    /*
    每次给出要争吵的猴子a和b,用并查集判断如果他们是朋友输出-1
    如果不是,找出a,b在的堆的根A,B,分别合并A,B的左右孩子,再合并一下。
    之后把A,B的数据更改一下:权值除以2,左右孩子设为0,再插入到堆中即可。
    最后输出堆顶。
    */ 
    #include <iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int N = 100005;
    int m,n;
    int set[N];
    struct node
    {
        int l,r,dis,key;
    }tree[N];
    
    int find(int x) {return set[x] == x ? x : set[x] = find(set[x]);}
    
    int merge(int a,int b)
    {
        if(!a)
            return b;
        if(!b)
            return a;
        if(tree[a].key < tree[b].key)//大堆
            swap(a,b);
        tree[a].r = merge(tree[a].r,b);
        set[tree[a].r] = a;//并查
        if(tree[tree[a].l].dis < tree[tree[a].r].dis)
            swap(tree[a].l,tree[a].r);
        if(tree[a].r)
            tree[a].dis = tree[tree[a].r].dis + 1;
        else
            tree[a].dis = 0;
        return a;
    }
    
    int pop(int a)
    {
        int l = tree[a].l;
        int r = tree[a].r;
        set[l] = l;//因为要暂时删掉根,所以左右子树先作为根
        set[r] = r;
        tree[a].l = tree[a].r = tree[a].dis = 0;
        return merge(l,r);
    }
    
    int nextint()
    {
        char c;
        int ret = 0;
        while((c = getchar()) > '9' || c < '0')
            ;
        ret = c - '0';
        while((c = getchar()) >= '0' && c <= '9')
            ret = ret * 10 + c - '0';
        return ret;
    }
    
    void print(int a)
    {
        if(!a)
            return;
        print(a/10);
        putchar(a%10 + '0');
    }
    
    int main()
    {
        int a,b,i;
        while(~scanf("%d",&n))
        {
            for(i = 1;i <= n;i ++)
            {;
                tree[i].key = nextint();
                set[i] = i;
                tree[i].l = tree[i].r = tree[i].dis = 0;
            }
            m = nextint();
            while(m --)
            {
                a = nextint();
                b = nextint();
                int ra = find(a);
                int rb = find(b);
                if(ra == rb)
                    printf("-1
    ");
                else
                {
                    int rra = pop(ra);//ra左右子树合并
                    tree[ra].key /= 2;
                    ra = merge(rra,ra);//重新插入ra 找到合适的位置
                    int rrb = pop(rb);
                    tree[rb].key /= 2;
                    rb = merge(rrb,rb);
                    print(tree[merge(ra,rb)].key);
                    putchar(10);
                }
            }
        }
        return 0;
    }
    心若向阳,无谓悲伤
    折花枝,恨花枝,准拟花开人共卮,开时人去时。 怕相思,已相思,轮到相思没处辞,眉间露一丝。
  • 相关阅读:
    JS弹出下载对话框以及实现常见文件类型的下载
    什么是物理像素、虚拟像素、逻辑像素、设备像素,什么又是 PPI, DPI, DPR 和 DIP
    学会git玩转github,结尾有惊喜!有惊喜!有惊喜!
    Menu实现逻辑
    控件保持多种绘图状态的做法
    2个函数宏技巧
    绘图 Painter转接口封装的方式
    DirectUI消息循环的简单封装
    c++以代理的方式来实现接口化编程
    c++对象工厂
  • 原文地址:https://www.cnblogs.com/L-Memory/p/6158297.html
Copyright © 2020-2023  润新知