bzoj - 1455 【可并堆 + 并查集】 这一类的好题!!!

Description

罗马皇帝很喜欢玩杀人游戏。 他的军队里面有n个人,每个人都是一个独立的团。最近举行了一次平面几何测试,每个人都得到了一个分数。 皇帝很喜欢平面几何,他对那些得分很低的人嗤之以鼻。他决定玩这样一个游戏。 它可以发两种命令: 1. Merger(i, j)。把i所在的团和j所在的团合并成一个团。如果i, j有一个人是死人,那么就忽略该命令。 2. Kill(i)。把i所在的团里面得分最低的人杀死。如果i这个人已经死了,这条命令就忽略。 皇帝希望他每发布一条kill命令,下面的将军就把被杀的人的分数报上来。(如果这条命令被忽略,那么就报0分)

input

第一行一个整数n(1<=n<=1000000)。n表示士兵数,m表示总命令数。 第二行n个整数,其中第i个数表示编号为i的士兵的分数。(分数都是[0..10000]之间的整数) 第三行一个整数m(1<=m<=100000) 第3+i行描述第i条命令。命令为如下两种形式: 1. M i j 2. K i

output

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

Sample Input

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

Sample Output

10
100
0
66

思路: 很明显的可并堆裸题, 不过带并查集, 注意的坑点就是进行可并时要是两个点的坐在集合的根之间进行并.. 还有最大的肯定就是对于删除的这个根它的父亲还是要设置为它左右儿子合并后的新的根节点, 因为此时删除的这个点的子树还有很多点是以它根的, 所以不能设置为空, 否则RE致死… 这道就是可并堆中带并查集的经典题!!!

AC Code

const int maxn = 1e6 + 5;
int root[maxn];
struct Ltree {
    int ls[maxn], rs[maxn];
    ll val[maxn];
    int Un(int x, int y){
        if (!x || !y) return x+y;
        if (val[x] > val[y]) swap(x,y);
        rs[x] = Un(rs[x], y);
        swap(ls[x], rs[x]);
        root[ls[x]] = root[rs[x]] = x;
        root[x] = x;  // 要写并查集就在这写就行乐
        return x;
    }
    void pop(int x) {
        root[ls[x]] = ls[x];
        root[rs[x]] = rs[x];
        root[x] = Un(ls[x], rs[x]);
        // 注意这里把删除的点的父亲重新设置为新的根节点.
    }
}heap;
int vis[maxn];
int Find(int x) {
    return root[x] == x ? x : root[x] = Find(root[x]);
}
void solve() {
    int n; scanf("%d", &n);
    for (int i = 1 ; i <= n ; i ++) {
        root[i] = i;
        int x; scanf("%d", &x);
        heap.val[i] = x;
    }
    int m; scanf("%d", &m);
    while(m--) {
        char op[5]; scanf("%s", op);
        int i, j;
        if (op[0] == 'M') {
            scanf("%d%d", &i, &j);
            if (vis[i] || vis[j]) continue;
            int fi = Find(root[i]), fj = Find(root[j]);
            if (fi == fj) continue;
            root[fi] = root[fj] = heap.Un(fi, fj);
        }
        else {
            scanf("%d", &i);
            if (vis[i]) puts("0");
            else {
                int fx = Find(root[i]); vis[fx] = 1;
                printf("%lld\n", heap.val[fx]);
                heap.pop(fx);
            }
        }
    }
}

你可能感兴趣的:(可并堆/左偏树)