您的位置:首页 > 其它

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

2016-12-10 21:13 405 查看
题目链接: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
;
struct node
{
int l,r,dis,key;
}tree
;

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\n");
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;
}


心若向阳,无谓悲伤
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: