您的位置:首页 > 其它

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

2015-07-28 09:39 405 查看
题目链接: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].lef
4000
t = 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",<ree[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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: