原题链接点击打开链接
LGOJ1456点击打开链接
题目大意呢就是
一开始有n只孤独的猴子,然后他们要打m次架,每次打架都会把自己和朋友中最强的拉出来跟别人打,打完之后两人战斗力就会减半。每次打完架就会成为朋友(正所谓不打不相识....)。问每次打完架之后那俩猴子最强的朋友战斗力还有多少。朋友不打架,若朋友打架就输出-1.
注意 有多组输入数据
分析
1.每次要找自己和朋友中最强的,比较快的方法就是堆...
2.打完架之后就成了朋友,意味着需要经常把两个堆进行合并
3.综上两点,需要用到一个很有意思的数据结构 左偏树
(我也不知道哪个左撇子发明的这个东西....干嘛不弄成右偏树...)
对这就是一道非常基础的左偏树练习题
那么关于左偏树 稍作介绍
左偏树是一棵二叉树,且满足堆的所有性质
左偏树区别于普通堆的一个重要性质:
对于每一个节点,其左儿子的距离大于等于右儿子的距离
这里的距离定义为:该节点到其子树的叶子节点最少进过的边数。其中叶子节点(也称外节点)的距离为0,空节点为-1。
利用上面的性质,每次插入都归到右边,可以在LogN的时间里实现堆的合并
具体学习可以参考2005年国家集训队论文 黄源河:《左偏树的性质及其应用》
到这里MonkeyKing的问题就可以完美的解决了....
去找至尊宝玩了....再见........
var i,j,k,n,m,x,y,s,newroot,xx,yy,sx,sy,l,r,tt:longint;
v,left,right,fa,dis:array[-10..300007]of longint;
function max(a,b:longint):longint;
begin
if a>b then exit(a); exit(b);
end;
function getfa(x:longint):longint;
begin
while fa[x]<>0 do x:=fa[x];
exit(x);
end;
procedure swap(var x,y:longint);
var t:longint;
begin
t:=x; x:=y; y:=t;
end;
function Merge(r1,r2:longint):longint;
begin
if r1=0 then exit(r2);
if r2=0 then exit(r1);
if v[r1]<v[r2] then swap(r1,r2);
right[r1]:=Merge(right[r1],r2);
fa[right[r1]]:=r1;
if dis[left[r1]]<dis[right[r1]] then swap(left[r1],right[r1]);
dis[r1]:=dis[right[r1]]+1;
exit(r1);
end;
function delete(root:longint):longint;
var l,r:longint;
begin
fa[left[root]]:=0;
fa[right[root]]:=0;
dis[root]:=0;
l:=left[root]; left[root]:=0;
r:=right[root]; right[root]:=0;
exit(Merge(l,r));
end;
begin
while not eof do
begin
readln(n);
for i:=1 to n do
begin readln(v[i]);
fa[i]:=0;
left[i]:=0; right[i]:=0;
dis[i]:=0; end;
dis[0]:=-1;
readln(m);
for i:=1 to m do
begin
readln(x,y);
xx:=getfa(x); yy:=getfa(y);
if xx=yy then begin writeln(-1); continue; end;
v[xx]:=trunc(v[xx]/2);
v[yy]:=trunc(v[yy]/2);
l:=delete(xx); r:=delete(yy);
l:=Merge(l,xx); r:=Merge(r,yy);
l:=Merge(l,r);
writeln(v[l]);
end;
end;
end.