HDU 1512 Monkey King(左偏树+并查集)

来源:互联网 发布:spss数据分析书推荐 编辑:程序博客网 时间:2024/06/05 18:03

题目链接:Click here

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

思路:两拨不认识得猴子决斗后认识,涉及到合并,于是想到并查集。又要求两拨猴子的最强战斗力,大顶堆比较合适,而堆得合并,用到了刚看到的左偏树。

    左偏树:(引用百度百科)    [性质1] 节点的键值小于或等于它的左右子节点的键值。    [性质2] 节点的左子节点的距离不小于右子节点的距离。    [性质3] 节点的距离等于它的右子节点的距离加1。    我们的印象中,平衡树是具有非常小的深度的,这也意味着到达任何一个节点所经过的边数很少。左偏树并不是为了快速访问所有的节点而设计的,它的目的是快速访问最小节点以及在对树修改后快速的恢复堆性质。从图中我们可以看到它并不平衡,由于性质2的缘故,它的结构偏向左侧,不过距离的概念和树的深度并不同,左偏树并不意味着左子树的节点数或是深度一定大于右子树。

代码:

#include <iostream>#include <cstring>#include <cstdio>#include <queue>#include <cstdlib>using namespace std;int father[100005];struct Monkey{    int left, right;    int dis;    int blood;} LTree[100005];int findx(int x){    if(x == father[x])return x;    return father[x] = findx(father[x]);}int merges(int x,int y){    int left, right;    if( x == 0 )        return y;    if( y == 0)        return x;    if( LTree[x].blood < LTree[y].blood) //大顶堆        swap(x,y);    LTree[x].right = merges(LTree[x].right,y);    left = LTree[x].left;    right = LTree[x].right;    father[right] = x;   //修改并查集的根    if(LTree[left].dis < LTree[right].dis)        swap(LTree[x].left,LTree[x].right);    if(LTree[x].right == 0)        LTree[x].dis = 0;    else        LTree[x].dis = LTree[LTree[x].right].dis + 1;    return x;}int del(int x){//删除根节点,并合并左右子树    int left, right;    left = LTree[x].left;    right = LTree[x].right;    father[left] = left;    father[right] = right;    LTree[x].left = LTree[x].right = LTree[x].dis = 0;    return merges(left, right);}void fight(int a,int b){//两棵树根节点血量减半,并与子树再次合并    int left,right;    LTree[a].blood /= 2;    LTree[b].blood /= 2;    left = del(a);    right = del(b);    left = merges(left, a);    right = merges(right, b);    left = merges(left,right);    printf("%d\n",LTree[left].blood);}int main(){    int n, m, x, y, a, b;    while(scanf("%d",&n) != EOF)    {        for(int i = 1; i <= n; i++)        {            scanf("%d",&LTree[i].blood);            LTree[i].left = 0;            LTree[i].right = 0;            LTree[i].dis = 0;            father[i] = i;        }        scanf("%d",&m);        for(int i = 1; i <= m; i++)        {            scanf("%d%d",&x,&y);            a = findx(x);            b = findx(y);            if(a == b)                printf("-1\n");            else fight(a, b);        }    }    return 0;}
0 0