题意:
有n个猴子,每个猴子有一个能力值,猴子之间喜欢打架,打完架之后就变成好朋友了,就不会再打架了,现给出m个关系(x,y),表示猴子x要和猴子y打架,打完架之后这两个猴子的能力值会减半,然后输出它们这个朋友圈里德最大能力值
题解:
左偏树+并查集
显然要用左偏树来维护每个并查集里猴子的能力值
这里猴子打完架之后能力值会减半,所以相当于要在左偏树中pop这个点,然后再merge
注意:并查集和左偏树是两个独立的数据结构,之间没有影响关系,并查集只是单纯地维护连通性,而对左偏树的结构不产生影响
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#define ll long long
#define N 100010
using namespace std;
int fa[N],rs[N],ls[N],v[N],dis[N];
int gi() {
int x=0,o=1; char ch=getchar();
while(ch!='-' && (ch<'0' || ch>'9')) ch=getchar();
if(ch=='-') o=-1,ch=getchar();
while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
return o*x;
}
int find(int x) {
return x==fa[x]?x:fa[x]=find(fa[x]);
}
int merge(int x, int y) {
if(!x) return y;
if(!y) return x;
if(v[x]<v[y]) swap(x,y);
rs[x]=merge(rs[x],y);
fa[rs[x]]=x;
if(dis[rs[x]]>dis[ls[x]]) swap(rs[x],ls[x]);
if(rs[x]==0) dis[x]=0;
else dis[x]=dis[rs[x]]+1;
return x;
}
int pop(int x) {
int l=ls[x],r=rs[x];
fa[l]=l,fa[r]=r;
ls[x]=rs[x]=dis[x]=0;
return merge(l,r);
}
int main() {
int n,m;
while(~scanf("%d", &n)) {
for(int i=1; i<=n; i++) {
ls[i]=rs[i]=dis[i]=0;
fa[i]=i;
v[i]=gi();
}
m=gi();
while(m--) {
int x=gi(),y=gi(),p,q;
x=find(x),y=find(y);
if(x==y) {puts("-1");continue;}
else {
v[x]/=2;
p=pop(x),p=merge(p,x);
v[y]/=2;
q=pop(y),q=merge(q,y);
printf("%d
", v[merge(p,q)]);
}
}
}
return 0;
}