【题目】
题目描述:
罗马皇帝很喜欢玩杀人游戏。 他的军队里面有 个人,每个人都是一个独立的团。最近举行了一次平面几何测试,每个人都得到了一个分数。 皇帝很喜欢平面几何,他对那些得分很低的人嗤之以鼻。他决定玩这样一个游戏。 它可以发两种命令:
- Merger(i,j)。把 所在的团和 所在的团合并成一个团。如果 , 有一个人是死人,那么就忽略该命令。
- Kill(i)。把 所在的团里面得分最低的人杀死。如果 这个人已经死了,这条命令就忽略。 皇帝希望他每发布一条 Kill 命令,下面的将军就把被杀的人的分数报上来。(如果这条命令被忽略,那么就报 分)
输入格式:
第一行一个整数 ( ),表示士兵数。
第二行 个整数,其中第 个数表示编号为 的士兵的分数。(分数都是 之间的整数)
第三行一个整数 ( ),表示总命令数。
接下来 行分别描述 条命令,命令为如下两种形式:
- M i j
- K i
输出格式:
如果命令是 Kill,对应的请输出被杀人的分数。(如果这个人不存在,就输出 )
样例数据:
输入
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
【分析】
左偏树模板题。
对于 操作,可以维护一个小根堆,然后 操作就是合并两个堆,用左偏树就可以了。
【代码】
#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;
}