zoj - 3261 反向并查集、带权并查集

题意:有很多颗星球,各自有武力值,星球间有一些联系通道,现在发生战争,有一些联系通道会被摧毁,而一些星球会通过还没有被摧毁的联系通道直接或者间接联系能够联系到的武力值最高的星球求救(必须比自己的武力值高),如果有多个武力值都为最高的,那就联系一个编号最小的。现在给出一系列求救和摧毁的序列,一次执行,并对于每一个求救指令寻找合适的求救星球编号,如果没有可以求救的则输出 -1;

如我们所知,并查集并不能去删除一些关系,所以可以将查询操作离线反向读入,这样通道的破坏就变成修建,只要先将所有的询问和通道保存,然后遍历一边一开始存在的通道,除了将要被摧毁的通道外都加入并查集,之后反向处理命令,查询就直接输出命令,摧毁就建立通道。

注意合并时根据武力值大小,武力值大的作为父节点,若武力值相等则编号小的为父节点。

链接:zoj 3261

#include
#include
#include
#include
#include
#include
#include 
#include 
#include 
using namespace std;

const int maxn = 20000 + 10;
const int inf = 0x3f3f3f3f;

int n;

struct query {
    int b, c;
    int flag;
}a[50005];

int father[maxn];
int r[maxn];
int cnt, flag;
int power[maxn];

map< pair , int> edge;
map< pair , int> ::iterator it;

// 获取根结点
int getf(int x) {
    if(father[x] != x) {
        int t = father[x];
        father[x] = getf(father[x]);
        r[x] = max(r[x], r[t]);
    }
    return father[x];
}
// 合并两个元素所在的集合
void unions(int x, int y) {
    int rx = getf(x);
    int ry = getf(y);
    if(x == y) {
        return;
    }
    if(r[rx] > r[ry] || (r[rx]== r[ry] && rx < ry)) {
        father[ry] = rx;
    }
    else {
        father[rx] = ry;
    }
}

int main()
{
    int T, kcase = 1;
    int m;
    while(scanf("%d", &n) != EOF) {
        if(!kcase) {
            puts("");
        }
        else {
            kcase = 0;
        }
        edge.clear();
        for(int i = 0; i < n; i++) {
            scanf("%d", &power[i]);
            father[i] = i;
            r[i] = power[i];
        }
        scanf("%d", &m);
        int b, c;
        for(int i = 0; i < m; i++) {
            scanf("%d %d", &b, &c);
            if(b > c) {
                swap(b, c);
            }
            edge[make_pair(b, c)] = 1;
        }
        int q;
        scanf("%d", &q);
        char str[15];
        for(int i = 0; i < q; i++) {
            scanf("%s", str);
            if(str[0] == 'q') {
                scanf("%d", &a[i].b);
                a[i].flag = 0;
            }
            else {
                scanf("%d %d", &a[i].b, &a[i].c);
                if(a[i].b > a[i].c) {
                    swap(a[i].b, a[i].c);
                }
                edge[make_pair(a[i].b, a[i].c)] = 0;
                a[i].flag = 1;
            }
        }
        pair temp;
        for(it = edge.begin(); it != edge.end(); ++it) {
            if(it -> second) {
                temp = it -> first;
                unions(temp.first, temp.second);
            }
        }
        stack sta;
        for(int i = q - 1; i >= 0; i--) {
            if(a[i].flag) {
                unions(a[i].b, a[i].c);
            }
            else {
                if(r[getf(a[i].b)] <= power[a[i].b]) {
                    sta.push(-1);
                }
                else {
                    sta.push(getf(a[i].b));
                }
            }
        }
        while(!sta.empty()) {
            printf("%d\n", sta.top());
            sta.pop();
        }
    }
    return 0;
}

你可能感兴趣的:(并查集)