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

题意:

给出n个星球之间的连接关系,再给出Q个查询,有两种操作:(1)destroy a b:删除a,b之间的边;(2)query a:查询与a直接连接或间接连接的星球中能量值最大的星球,若最大的不止一个,输出编号最小的

分析:

因为要查询一个联通块,不难想到用并查集,但存在删边的操作,并查集又不能直接处理删边,考虑离线后,反方向处理,删边就变成加边;开始先将m条边加入并查集,但在查询中要删除的边不要加入,反向查询时再来加

因为查询时的条件限制,合并时考虑:能量小的点 --> 能量大的点,能量相等时,小编号 --> 大编号;注意输出格式!!!

代码:

#include <bits/stdc++.h>
#define pii pair<int,int>
#define f first
#define s second
using namespace std;
const int MAXN = 1e5+15;
int n,m,pre[MAXN],power[MAXN],res[MAXN],Q;
pii e[MAXN];
struct node{
    int op,x,y;
}q[MAXN];
int Find(int x){
    return pre[x] == x ? x : pre[x] = Find(pre[x]);
}
void mix(int x,int y){
    int fx = Find(x),fy = Find(y);
    if(fx != fy){
        if(power[fx] > power[fy]) pre[fy] = fx;
        else if(power[fx] == power[fy]) pre[max(fx,fy)] = min(fx,fy);
        else pre[fx] = fy;
    }
}
string s;
map<pii,int> p;                                     //标记查询中要删的边
int main(){
    bool vis = false;
    while(cin >> n){
    p.clear();
    for(int i = 0;i < n; ++i) pre[i] = i;
    for(int i = 0;i < n; ++i) cin>>power[i];
    cin >> m;
    for(int i = 0;i < m; ++i){
        cin>>e[i].f>>e[i].s;
        if(e[i].s < e[i].f) swap(e[i].f,e[i].s);   //统一小号在前,因为边是无向的
    }
    cin >> Q;
    for(int i = 0;i < Q; ++i){
        cin >> s;
        if(s[0] == 'q'){
            q[i].op = 1;
            cin >> q[i].x;
        }
        else{
            q[i].op = 0;
            cin >> q[i].x >> q[i].y;
            if(q[i].y < q[i].x) swap(q[i].x,q[i].y);
            p[pii(q[i].x,q[i].y)] = 1;
        }
    }
    for(int i = 0;i < m; ++i){
        if(!p[e[i]]) mix(e[i].f,e[i].s);
    }
    int len = 0;
    for(int i = Q-1; ~i ; --i){
        if(q[i].op){
            int fa = Find(q[i].x);
            res[len++] = power[fa] > power[q[i].x] ? fa : -1;
        }
        else mix(q[i].x,q[i].y);
    }
    if(vis) puts("");
    else vis = true;
    for(int i = len-1; ~i ; --i) cout << res[i] << '\n';
  }
  return 0;
}

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值