[HDU1512]Monkey King

原題鏈接點擊打開鏈接

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.
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章