罗马皇帝很喜欢玩杀人游戏。 他的军队里面有n个人,每个人都是一个独立的团。最近举行了一次平面几何测试,每个人都得到了一个分数。 皇帝很喜欢平面几何,他对那些得分很低的人嗤之以鼻。他决定玩这样一个游戏。 它可以发两种命令:
- Merger(i, j)。把i所在的团和j所在的团合并成一个团。如果i, j有一个人是死人,那么就忽略该命令。
- Kill(i)。把i所在的团里面得分最低的人杀死。如果i这个人已经死了,这条命令就忽略。
皇帝希望他每发布一条kill命令,下面的将军就把被杀的人的分数报上来。(如果这条命令被忽略,那么就报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
(这罗马皇帝闲着无聊。。。)
代码
#include<bits/stdc++.h>
using namespace std;
#define maxn 1000010
int n,m;//n表示士兵数,m表示命令数
int a[maxn];//士兵的分数
int fa[maxn];//这个点的祖宗节点
bool vis[maxn];//判断这个点是否死亡 (false为活,true为死)
int rch[maxn],lch[maxn];//这个点的左儿子和右儿子
int dis[maxn];
int find(int x) // 找这个点的祖宗
{
if(x==fa[x]) return x;
else return fa[x]=find(fa[x]);
}
int merge(int x,int y) //合并两个堆
{
if(x==0||y==0) return x+y;
if(a[x]>a[y])
swap(x,y);//为维护小根堆,若是a[x]> a[y],就将小的与大的交换
rch[x]=merge(rch[x],y);//如果这个数没有小于现在的x,便将它与x的右儿子比较
if(dis[rch[x]]>dis[lch[x]])
swap(lch[x],rch[x]);//如果右边比左边的权值大,不符合左偏树定义 ,那就将左儿子和右儿子交换
dis[x]=dis[rch[x]]+1; //这个点的权值加1
return x;
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
fa[i]=i;
scanf("%d",&a[i]);
}
scanf("%d",&m);
for(int i=1;i<=m;i++)
{
char ch[5];
scanf("%s",ch);
if(ch[0]=='M')
{
int x,y;
scanf("%d%d",&x,&y);
if(vis[x]==true||vis[y]==true)
continue; //如果两个人中有一个无了,就跳出
x=find(x);//找到x的祖宗
y=find(y);//找到y的祖宗
if(x!=y)//如果他们的祖宗不是一个,即不在一个集合中
fa[x]=fa[y]=merge(x,y);//就把他们合并
}
if(ch[0]=='K')//当下达的是kill指令时
{
int x;
scanf("%d",&x);
if(vis[x]==true)//如果这人已经没了
{
printf("0\n");//直接输出0
continue;
}
x=find(x);//找到x的祖宗,即x所在集合的根(小根堆)
vis[x]=true;//这个人被无了
printf("%d\n",a[x]);//将他的分数输出
int head=merge(lch[x],rch[x]);//因为这个时候根节点没了,就要将左右儿子合并重新形成一个堆
fa[x]=head;
fa[head]=head;
}
}
return 0;
}
左偏树还是比较冷门的吧,一般都不怎么会考,,,,