P1456 Monkey King(左偏树)

洛谷题目传送门

题目描述

曾经在一个森林中居住着 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;
}
上一篇:Monkey King


下一篇:基本的DOS命令