洛谷P2713 罗马游戏

sloj bzoj1455. 罗马游戏

题目描述

罗马皇帝很喜欢玩杀人游戏。 他的军队里面有n个士兵,每个士兵都是一个独立的团。最近举行了一次平面几何测试,每个士兵都得到了一个分数。 皇帝很喜欢平面几何,他对那些得分很低的士兵嗤之以鼻。

他决定玩这样一个游戏。 它可以发两种命令:

  • M i j 把i所在的团和j所在的团合并成一个团。如果i,j有一个士兵是死人,那么就忽略该命令。
  • K i 把i所在的团里面得分最低的士兵杀死。如果i这个士兵已经死了,这条命令就忽略。

皇帝希望他每发布一条 K i 命令,下面的将军就把被杀的士兵的分数报上来 (如果这条命令被忽略,那么就报0分)。

保证士兵的分数互不相同。

输入格式

第一行一个整数n,表示士兵数。

第二行n个整数a1,a2,an,其中ai 表示编号为i的士兵的分数。

第三行一个整数m

3+i行描述第i条命令。命令为如下两种形式:M i j 或 K i

输出格式

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

输入输出样例

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

说明/提示

1n1061m1050ai107, 注意测试数据中 M i j 的i,j可能在同一个团中。

很明显,对于M指令来说,我们应该使用并查集来维护

然后对于K嘛……好吧,我也不是很清楚

不过有一点是明确的,那就是我们应该用堆(优先队列)来维护

再结合第一个的合并操作,这时就会想到用可并堆,也就是左偏树来维护

有了这个思路以后再来看,这不就是模板题嘛,完事

上代码

#include<bits/stdc++.h>
using namespace std;
int n,m,a[1000010],fa[1000010],root[1000010],ch[1000010][2],dis[1000010];
bool dead[1000010];
int find_(int x){
    return fa[x]==x?x:fa[x] = find_(fa[x]);
}
int merge(int x,int y){
    if(!x||!y) return x+y;
    if(a[x]>a[y]) swap(x,y);
    ch[x][1] = merge(ch[x][1],y);
    if(dis[ch[x][0]]<dis[ch[x][1]]) swap(ch[x][0],ch[x][1]);
    dis[x] = dis[ch[x][1]]+1;
    return x;
}
int main(){
    scanf("%d",&n);
    for(int i = 1;i<=n;i++){
        scanf("%d",&a[i]);
        fa[i] = i;
        root[i] = i;
    }
    scanf("%d",&m);
    for(int i = 1;i<=m;i++){
        char c;int x,y;
        cin>>c;
        if(c=='M'){
            scanf("%d%d",&x,&y);
            if(dead[x]||dead[y]) continue;
            x = find_(x),y = find_(y);
            if(x==y) continue;
            fa[x] = y;
            root[y] = merge(root[x],root[y]);
        }else{
            scanf("%d",&x);
            if(dead[x]){
                puts("0");
                continue;
            }
            x = find_(x);
            printf("%d\n",a[root[x]]);
            dead[root[x]] = true;
            root[x] = merge(ch[root[x]][0],ch[root[x]][1]);
        }
    }
    return 0;
}

 

posted @ 2022-12-23 21:57  cztq  阅读(31)  评论(0)    收藏  举报