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