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

时间:2023-03-09 01:47:11
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",&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\n",T[merge(x,y)].v);
}
}
}return 0;
}