BZOJ1455 罗马游戏 左偏树 可并堆

欢迎访问~原文出处——博客园-zhouzhendong

去博客园看该题解


题目传送门 - BZOJ1455


题意概括

  n个人,2种操作。

  一种是合并两个人团,一种是杀死某一个人团的最弱的人。


题解

  左偏树裸题。

  直接上板子。


 

代码

#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cstdlib>
#include <cmath>
using namespace std;
const int N=1000005;
bool isd(char ch){
	return '0'<=ch&&ch<='9';
}
void read(int &x){
	x=0;
	char ch=getchar();
	while (!isd(ch))
		ch=getchar();
	while (isd(ch))
		x=(x<<1)+(x<<3)+ch-48,ch=getchar();
}
int n,m,killed[N];
int fa[N],ls[N],rs[N],npl[N],val[N];
int getf(int a){
	while (fa[a])
		a=fa[a];
	return a;
}
int merge(int a,int b){
	if (!a||!b)
		return a+b;
	if (val[a]>val[b])
		swap(a,b);
	rs[a]=merge(rs[a],b);
	fa[rs[a]]=fa[ls[a]]=a;
	if (npl[rs[a]]>npl[ls[a]])
		swap(rs[a],ls[a]);
	npl[a]=npl[rs[a]]+1;
	return a;
}
int main(){
	scanf("%d",&n);
	for (int i=1;i<=n;i++)
		read(val[i]),fa[i]=ls[i]=rs[i]=npl[i]=0;
	memset(killed,0,sizeof killed);
	scanf("%d",&m);
	for (int i=1;i<=m;i++){
		char op[2];
		int a,b;
		scanf("%s%d",op,&a);
		if (op[0]=='K'){
			if (killed[a]){
				puts("0");
				continue;
			}
			a=getf(a);
			killed[a]=1;
			printf("%d\n",val[a]);
			fa[ls[a]]=fa[rs[a]]=0;
			merge(ls[a],rs[a]);
			ls[a]=rs[a]=npl[a]=0;
		}
		else {
			scanf("%d",&b);
			if (!killed[a]&&!killed[b]&&getf(a)!=getf(b))
				merge(getf(a),getf(b));
		}
	}
	return 0;
}

  

 

posted @ 2017-12-19 20:11  zzd233  阅读(245)  评论(0编辑  收藏  举报