zoj3261 带权并查集

题目链接在这里

题目大意

n个星球,每个星球有一个防御值,一共有m条路,连接x星球和y星球。现在发生星际战争了,a星球要寻求帮助,它只能寻求比它的防御值大的星球的帮助(相同的防御值的话取下标较小的那个),其中会破坏道路再进行寻求帮助。问每次询问时,某星球该找哪个星球寻求帮助。

思路

这是一个并查集问题,如果顺着题目的思路来的话,要进行拆边。但是并查集没有拆边的功能,所以我们转换思路,先处理最后的询问,然后依次往前进行路的合并。这样就简单一点。

代码如下

#include <cstdio>
#include <cstring>
#include <cmath>
#include <iostream>
#include <algorithm>
#define rep(i, x) for(int i = 0; i < x; ++i)
#define clr(x) memset(x, 0, sizeof(x))
using namespace std;

const int MaxN = 10010;
const int MaxM = 20010;
const int MaxQ = 50010;

struct Query{
    bool flag;
    int x, y;
}query[MaxQ];

struct Edge{
    int y, nxt;
}edge[MaxM * 2];

int n, m, q;
int r[MaxN], par[MaxN];
int head[MaxN], tol;
int x[MaxM], y[MaxM];
int ans[MaxQ], cnt;

void addEdge(int x, int y){
    edge[tol].y = y;
    edge[tol].nxt = head[x];
    head[x] = tol++;
}

void init(){
    rep(i, MaxN)    par[i] = i;
    memset(head, -1, sizeof(head));
    tol = 0;
    cnt = 0;
}

int Find(int x){
    if(x == par[x]) return x;
    return par[x] = Find(par[x]);
}

bool unite(int x, int y){
    x = Find(x);
    y = Find(y);
    if(x == y)  return false;
    if(r[x] > r[y] || r[x] == r[y] && x < y)
        par[y] = x;
    else
        par[x] = y;
    return true;
}

void solve(){
    rep(i, m){
        int xx = x[i];
        int yy = y[i];
        bool flag = false;
        for(int j = head[xx]; j != -1; j = edge[j].nxt){
            if(edge[j].y == yy){
                flag = true;
                break;
            }
        }
        if(flag)    continue;
        unite(xx, yy);
    }
    for(int i = q - 1; i >= 0; --i){
        if(query[i].flag){
            unite(query[i].x, query[i].y);
        }
        else{
            int x = query[i].x;
            int fx = Find(x);
            if(r[fx] <= r[x]) ans[cnt++] = -1;
            else ans[cnt++] = fx;
        }
    }

    for(int i = cnt - 1; i >= 0; --i)
        printf("%d\n", ans[i]);
}
int main(){
    int tag = 0;
    while(~scanf("%d", &n)){
        init();
        if(tag++)   printf("\n");
        rep(i, n)
            scanf("%d", &r[i]);
        scanf("%d", &m);
        rep(i, m){
            scanf("%d%d", &x[i], &y[i]);
        }
        scanf("%d", &q);
        char str[10];
        rep(i, q){
            scanf("%s", str);
            if(strcmp(str, "query") == 0){
                query[i].flag = false;
                scanf("%d", &query[i].x);
            }
            else{
                query[i].flag = true;
                scanf("%d%d", &query[i].x, &query[i].y);
                addEdge(query[i].x, query[i].y);
                addEdge(query[i].y, query[i].x);
            }
        }
        solve();
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Never__Give_Up_/article/details/86322723