题目描述
曾经在一个森林中居住着 N 只好斗的猴子。在最初他们我行我素,互不认识。但是猴子们不能避免争吵,且两只猴子只会在不认识对方时发生争吵,当争吵发生时,双方会邀请它们各自最强壮的朋友并发起决斗(决斗的为各自最强壮的朋友)。当然,在决斗之后两只猴子和他们各自的伙伴都认识对方了(成为朋友),虽然他们曾经有过冲突,但是他们之间绝不会再发生争吵了。
假设每只猴子有一个强壮值,强壮值将在一场决斗后减少为原先的一半(例如 10 会减少到 5,而 5 会减少到 2,即向下取整)。
我们也假设每只猴子都认识它自己(是自己的朋友)。即当他是他朋友中最强壮的,他自己就会去决斗。
解题思路
左偏树的模板,不会左偏树的可以看左偏树学习记录
决斗时,我们把两个根节点分别从左偏树中删除,修改全职之后在合并进去,最后把两颗左偏树合并就行了
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+7;
int rot[N],lson[N],rson[N],val[N],dis[N];
int Find(int x)
{
if(x==rot[x]) return x;
return rot[x]=Find(rot[x]);
}
int Merge(int x,int y)
{
if(!x||!y) return x+y;
if(val[x]<val[y]) swap(x,y);
rson[x]=Merge(rson[x],y);
if(dis[rson[x]]>dis[lson[x]]) swap(lson[x],rson[x]);
dis[x]=dis[rson[x]]+1;
return x;
}
void Fight(int x)
{
val[x]/=2;
int rt=Merge(lson[x],rson[x]);
lson[x]=rson[x]=dis[x]=0;
rot[x]=rot[rt]=Merge(x,rt);
}
int n,m;
int main()
{
while(scanf("%d",&n)!=EOF)
{
for(int i=1;i<=n;i++)
{
scanf("%d",&val[i]);
rot[i]=i;
dis[i]=0;
lson[i]=0;
rson[i]=0;
}
scanf("%d",&m);
while(m--)
{
int x,y;
scanf("%d%d",&x,&y);
x=Find(x);
y=Find(y);
if(x==y) printf("-1\n");
else
{
Fight(x);
Fight(y);
x=Find(x);
y=Find(y);
rot[x]=rot[y]=Merge(x,y);
printf("%d\n",val[rot[x]]);
}
}
}
return 0;
}