• 【并查集】Connections in Galaxy War ZOJ


    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;
    }
    
  • 相关阅读:
    CSS3 鲜为人知的属性-webkit-tap-highlight-color的理解
    14 个折磨人的 JavaScript 面试题
    JavaScript 开发的45个技巧2
    JavaScript 开发的45个技巧
    JavaScript 中的 this !
    JavaScript里的循环方法:forEach,for-in,for-of
    JS类型判断typeof PK {}.toString.call(obj)
    Object.prototype.toString()
    MinGW gcc 生成动态链接库 dll 的一些问题汇总 (补充)
    Selenium之偷懒教程
  • 原文地址:https://www.cnblogs.com/streamazure/p/13499308.html
Copyright © 2020-2023  润新知