题目
有n只猴子,他们要打m次架,每次打架呢,都会拉上自己朋友最牛叉的出来跟别人打,打完之后战斗力就会减半,每次打完架就会成为朋友。问每次打完架之后那俩猴子最牛叉的朋友战斗力还有多少,若朋友打架就输出-1。
分析
二叉堆的合并比较慢,那么二项堆和FIBONACCI堆我都不会,所以可以用一种较中和的数据结构,左偏树,同时用并查集维护即可
代码
#include <cstdio>
#include <algorithm>
struct leftist_tree{int l,r,key,dis;}e[100001];
int n,m,f[100001];
int in(){
int ans=0; char c=getchar();
while (c<48||c>57) c=getchar();
while (c>47&&c<58) ans=ans*10+c-48,c=getchar();
return ans;
}
int getf(int u){
int r=u,i=u,j;
while (f[r]!=r) r=f[r];
while (i!=r) j=f[i],f[i]=r,i=j;
return r;
}
void print(int ans){if (ans>9) print(ans/10); putchar(ans%10+48);}
int merge(int x,int y){
if (!x) return y;//没了
if (!y) return x;//没了
if (e[x].key<e[y].key) std::swap(x,y);//左偏,所以要交换
e[x].r=merge(e[x].r,y);//用右子树合并
int l=e[x].l,r=e[x].r; f[r]=x;
if (e[l].dis<e[r].dis) std::swap(e[x].l,e[x].r);//the same
e[x].dis=e[e[x].r].dis+1;//那么右边会有问题
return x;
}
int del(int x){//删除节点
int l=e[x].l; int r=e[x].r;
f[l]=l; f[r]=r;
e[x]=(leftist_tree){0,0,e[x].key,0};
return merge(l,r);//合并
}
void solve(int x,int y){
e[x].key>>=1; e[y].key>>=1;
int l=del(x); int r=del(y);//删除节点
l=merge(l,x); r=merge(r,y);
l=merge(l,r);//合并
if (e[l].key) print(e[l].key); else putchar('0');
}
int main(){
while (scanf("%d",&n)==1){
e[0]=(leftist_tree){0,0,e[0].key,-1};
for (int i=1;i<=n;i++)
e[i]=(leftist_tree){0,0,in(),0},f[i]=i;
m=in();
while (m--){
int x=getf(in()); int y=getf(in());
if (x==y) putchar('-'),putchar('1'); else solve(x,y);
putchar('\n');
}
}
return 0;
}