【并查集】Connections in Galaxy War ZOJ - 3261

Connections in Galaxy War ZOJ - 3261

题意:

\(n\)颗星星,编号\(0到n\)。第\(i\)颗星星的能量值为\(Pi\)。每颗星星可以向与它直接或间接相连、且能量值比它大(相等也不行)的星星求助,如果这样的星星有多颗,则向其中编号最小的星星求助。现给定\(m\)条星星之间的通道与\(q\)条指令,指令分两种:destroy:某条通道被摧毁;query:询问某颗星星的求助对象的编号。如果没有星星可求助,输出-1。

思路:

因为“直接或间接相连”这个条件,显然并查集可以做。但是并查集的合并过程中会压缩路径,使得删除某条路径时情况会变得非常复杂,显然不能顺着指令顺序来做。

所以我们先记录会被摧毁的通道,然后用最后仍然幸存的通道merge各个结点。接着反向遍历指令,遇到query就正常查询,遇到destroy就恢复这个通道。将答案全部入栈后再输出即可。

至于“编号最小”这一点,只要将通道u-v按u<v的原则储存,并且在find操作中将能量相同而编号更小的结点作为父节点即可。

const int maxn = 50000 + 100;

int fa[maxn];
LL power[maxn];
int n, m, q;
stack<int> s;
map< pair<int, int>, int> mp;

struct node {
    char str[20];
    int x, y;
}Q[maxn];

struct edge{
    int u,v;
}e[maxn];

int find(int p) {
    return fa[p] == p ? p : find(fa[p]);
}

void merge(int a, int b) {
    int r1 = find(a);
    int r2 = find(b);
    if (r1 != r2) {
        if (power[r1] > power[r2]) fa[r2] = r1;
        else if (power[r2] > power[r1]) fa[r1] = r2;
        //能量不同时,能量大的作父节点
        else {
            //能量相同时,编号小的作父节点
            if (r1 > r2) fa[r1] = r2;
            else fa[r2] = r1;
        }
    }
}

void init() {
    while (!s.empty()) s.pop();
    memset(Q, -1, sizeof(Q));
    memset(power, 0, sizeof(power));
    mp.clear();
    for (int i = 0; i < maxn; i++) fa[i] = i;
}

void Read() {
    for (int i = 0; i < n; i++) cin >> power[i];
    cin >> m;
    for (int i = 1; i <= m; i++) {
        cin >> e[i].u >> e[i].v;
        if (e[i].u > e[i].v) swap(e[i].u, e[i].v);
    }
    cin >> q;
    for (int i = 1; i <= q; i++) {
        cin >> Q[i].str;
        if (Q[i].str[0] == 'q') cin >> Q[i].x;
        else{
            cin >> Q[i].x >> Q[i].y;
            if (Q[i].x > Q[i].y) swap(Q[i].x, Q[i].y);
            pair<int, int> P;
            P = make_pair(Q[i].x, Q[i].y);
            mp[P] = 1;
            //标记不存在
        }
    }
}

void build() {
    for (int i = 1; i <= m; i++) {
        pair<int, int>P;
        P = make_pair(e[i].u, e[i].v);
        if (mp.count(P)) continue;
        //已标记不存在,跳过
        else merge(e[i].u, e[i].v);
    }
}

void solve() {
    for (int i = q; i >= 1; i--) {
        if (Q[i].str[0] == 'q') {
            int root = find(Q[i].x);
            if (power[root] > power[Q[i].x]) s.push(root);
            else s.push(-1);
        }
        else merge(Q[i].x, Q[i].y);
    }
    while (!s.empty()) {
        cout << s.top() << endl;
        s.pop();
    }
}

int main()
{
    //ios::sync_with_stdio(false);
    int first = 1;
    while (cin >> n) {
        if (!first) cout << endl;
        first = 0;
        init();
        Read();
        build();
        solve();
    }
    return 0;
}
posted @ 2020-08-13 22:25  StreamAzure  阅读(118)  评论(0编辑  收藏  举报