Bzoj1455 羅馬遊戲

傳送門:http://www.lydsy.com/JudgeOnline/problem.php?id=1455
題目描述:羅馬皇帝很喜歡玩殺人遊戲。 他的軍隊裏面有 n (1n106) 個人,每個人都是一個獨立的團。最近舉行了一次平面幾何測試,每個人都得到了一個分數。 皇帝很喜歡平面幾何,他對那些得分很低的人嗤之以鼻。他決定玩這樣一個遊戲。 它可以發兩種命令: 1.Merger(i,j) 。把i所在的團和j所在的團合併成一個團。如果 i,j 有一個人是死人,那麼就忽略該命令。 2.Kill(i) 。把i所在的團裏面得分最低的人殺死。如果 i 這個人已經死了,這條命令就忽略。 皇帝希望他每發佈一條 kill 命令,下面的將軍就把被殺的人的分數報上來。(如果這條命令被忽略,那麼就報 0 分)命令數 m (1m105)
題解: 是個左偏樹板子題,只需要一個 merge 操作,要注意的是刪除的時候要把刪除節點父親變成 merge 後的節點並把那個節點的父親賦爲自己。

#include<bits/stdc++.h>
const int N = 1e6 + 10;
template <typename T> void read(T &x) {
    x = 0; char c = getchar();
    for (; !isdigit(c); c = getchar());
    for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
}
struct Node{
    int val, h;
    Node *lc, *rc;
}Nil[N];
int n, m, x, y, fa[N];
bool killed[N];
char op[5];
int find(int x) {return fa[x] == x ? x : find(fa[x]);}
Node *merge(Node *a, Node *b) {
    if (a == Nil) return b;
    if (b == Nil) return a;
    if (a -> val > b -> val) std::swap(a, b);
    a -> rc = merge(a -> rc, b);
    if (a -> lc -> h < a -> rc -> h) std::swap(a -> lc, a -> rc);
    a -> h = a -> rc -> h + 1;
    return a;
}
int main() {
    freopen("tree.in", "r", stdin);
    freopen("tree.out", "w", stdout);
    read(n);
    for (int i = 1; i <= n; i++)
        read((Nil+i) -> val), fa[i] = i, 
        (Nil+i) -> lc = Nil, (Nil+i) -> rc = Nil, (Nil+i) -> h = 1;
    Nil -> lc = Nil; Nil -> rc = Nil;
    read(m);
    while (m--) {
        scanf("%s", op);
        if (op[0] == 'M') {
            read(x); read(y);
            if (killed[x] || killed[y] || (x = find(x)) == (y = find(y))) continue;
            fa[x] = fa[y] = merge(Nil+x, Nil+y) - Nil;
        }else {
            read(x);
            if (killed[x]) {printf("0\n"); continue;}
            printf("%d\n", (Nil + (x = find(x))) -> val);
            killed[x] = 1;
            fa[fa[x] = merge((Nil + x) -> lc, (Nil + x) -> rc) - Nil] = fa[x];
        }
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章