HDU 1512 Monkey King(左偏樹)
阿新 • • 發佈:2019-02-15
題意:
有
題解:
左偏樹。
AC程式碼:
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
struct node
{
int l,r;
int dis;
int val;
}ltree[100005];
int par[100005];
int getfather(int x)
{
return par[x] == x?x:par[x]=getfather(par[x]);
}
int merge(int x,int y)//返回合併後的根
{
int l,r;
//插入的樹為空時直接返回x (y),也就是合併完的樹
if(x==0)return y;
if(y==0)return x;
if(ltree[x].val<ltree[y].val) //大頂堆
{
swap(x,y);
}
ltree[x].r = merge(ltree[x].r,y);//遞迴合併右子樹 和 y
l = ltree[x].l;
r = ltree[x].r;
par[r] = x; //並查集合並,更新右子樹的根
if(ltree[l].dis<ltree[r].dis)
{
//必須遵守左偏樹的性質,左節點的距離不小於右節點的距離
swap(ltree[x].l,ltree[x].r);
}
if(ltree[x].r==0)//如果沒有右子樹 則距離為0
{
ltree[x].dis = 0;
}
else ltree[x].dis = ltree[ltree[x].r].dis+1 ;
return x;
}
int pop(int x)//返回刪除根以後左右子樹合併的根
{
int l,r;
l = ltree[x].l;
r = ltree[x].r;
//因為要暫時刪掉根,所以左右子樹先作為根
par[l] = l;
par[r] = r;
ltree[x].l = 0;
ltree[x].r = 0;
ltree[x].dis = 0;
return merge(l,r);
}
int main()
{
int n,m;
while(cin>>n)
{
for(int i=1;i<=n;i++)
{
scanf("%d",<ree[i].val);
ltree[i].l = 0;
ltree[i].r = 0;
ltree[i].dis = 0;
}
for(int i=1;i<=n;i++)par[i] = i;
scanf("%d",&m);
int a,b;
int fa,fb;
int l,r;
while(m--)
{
scanf("%d%d",&a,&b);
fa = getfather(a);
fb = getfather(b);
if(fa==fb)puts("-1");
else
{
//單挑後減半
ltree[fa].val /= 2;
ltree[fb].val /= 2;
//刪除最大的兩個值,再與新的值合併
l = pop(fa),r=pop(fb);
l = merge(l,fa);
r = merge(r,fb);
l = merge(l,r);
printf("%d\n",ltree[l].val);
}
}
}
return 0;
}