【BZOJ 1455】罗马游戏

【题目】

题目描述:

罗马皇帝很喜欢玩杀人游戏。 他的军队里面有 n n 个人,每个人都是一个独立的团。最近举行了一次平面几何测试,每个人都得到了一个分数。 皇帝很喜欢平面几何,他对那些得分很低的人嗤之以鼻。他决定玩这样一个游戏。 它可以发两种命令:

  1. Merger(i,j)。把 i i 所在的团和 j j 所在的团合并成一个团。如果 i i j j 有一个人是死人,那么就忽略该命令。
  2. Kill(i)。把 i i 所在的团里面得分最低的人杀死。如果 i i 这个人已经死了,这条命令就忽略。 皇帝希望他每发布一条 Kill 命令,下面的将军就把被杀的人的分数报上来。(如果这条命令被忽略,那么就报 0 0 分)

输入格式:

第一行一个整数 n n 1 n 1000000 1\le n\le1000000 ),表示士兵数。

第二行 n n 个整数,其中第 i i 个数表示编号为 i i 的士兵的分数。(分数都是 [    0    ,    10000    ] [\;0\;,\;10000\;] 之间的整数)

第三行一个整数 m m 1 m 100000 1\le m\le 100000 ),表示总命令数。

接下来 m m 行分别描述 m m 条命令,命令为如下两种形式:

  1. M i j
  2. K i

输出格式:

如果命令是 Kill,对应的请输出被杀人的分数。(如果这个人不存在,就输出 0 0

样例数据:

输入
5
100 90 66 99 10
7
M 1 5
K 1
K 1
M 2 3
M 3 4
K 5
K 4

输出
10
100
0
66


【分析】

左偏树模板题。

对于 2 2 操作,可以维护一个小根堆,然后 1 1 操作就是合并两个堆,用左偏树就可以了。


【代码】

#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 1000005
using namespace std;
char op[10];
int val[N],dis[N],father[N],son[N][2];
int find(int x)
{
	if(father[x]==x)  return x;
	return father[x]=find(father[x]);
}
int Merge(int x,int y)
{
	if(!x||!y)  return x+y;
	if(val[x]>val[y])  swap(x,y);
	son[x][1]=Merge(son[x][1],y);
	father[son[x][1]]=x;
	if(dis[son[x][0]]<dis[son[x][1]])
	  swap(son[x][0],son[x][1]);
	dis[x]=dis[son[x][1]]+1;
	return x;
}
void Pop(int x)
{
	val[x]=-1;
	father[son[x][0]]=son[x][0];
	father[son[x][1]]=son[x][1];
	father[x]=Merge(son[x][0],son[x][1]);
}
int main()
{
	int n,m,i,x,y;
	scanf("%d",&n);
	for(i=1;i<=n;++i)
	  father[i]=i,scanf("%d",&val[i]);
	scanf("%d",&m);
	for(i=1;i<=m;++i)
	{
		scanf("%s%d",op,&x);
		if(op[0]=='M')
		{
			scanf("%d",&y);
			if(val[x]==-1||val[y]==-1||find(x)==find(y))  continue;
			x=find(x),y=find(y),Merge(x,y);
		}
		else
		{
			if(val[x]==-1)  puts("0");
			else  printf("%d\n",val[find(x)]),Pop(find(x));
		}
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/forever_dreams/article/details/88244475