[洛谷多校第三场] E.Anan and Minecraft[并查集]

Anan and Minecraft

题意

初始给定两个点数一样的空图,在每个时刻会有一些连边操作,在每个时刻,判断两个图任意两点的连通性是否相同

思路

用并查集维护连通性,用 队列 维护操作序列。例如,每次在图1连u, v。我们可以认为,是让u, v连通,并把这条边加入图2的队列。如果图2 u, v不连通,那么就保存在图2的队列中,用两个队列让两个图在一次操作前是面对相同局面的,即如果在加入本次操作对应的这条边之前,如果把两个队列都清空,此时两个图是相同连通性的,即等价。

或者我们可以这样想:每一次连u, v的操作,是维护u所在集合和v所在集合的连通性,那么我们只要把这个u, v连通性的询问放在另一个图的队列里,连通就pop掉,不连通就存在队列中,不从边的角度理解,而是从集合的角度理解。

std中有个很好的处理就是面对多个含义相同的数组(fa1, fa2),用一个数组指针做函数名,有效简化了代码。

手残把find(fa1, u) == find(fa1, v) 打错了,要注意判断连不连通是用find函数啊!

代码

#include<cstdio>
#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<stack>
#include<set>
#define NDEBUG
#include <assert.h>
using namespace std;
typedef vector<int> vi;
typedef long long ll;
typedef unsigned long long ull;
typedef double db;

inline int read() {
    int x = 0, f = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9') {
        if(ch == '-') f = -1;
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9') {
        x = (x << 1) + (x << 3) + (ch ^ 48);
        ch = getchar();
    }
    return x * f;
}

#define endl '\n'
#define rd read()
#define pb push_back
#define mst(a, b) memset((a), (b), sizeof(a));
#define inf 0x3f3f3f3f
#define linf 0x3f3f3f3f3f3f3f3f
#define ls (u << 1)
#define rs (u << 1 | 1)
#define mod ((int)1e9+7)
#define maxn (int)(1e5+5)

int n, m;

int fa1[maxn], fa2[maxn];

void init(int *fa) {for(int i = 0; i < maxn; ++i) fa[i] = i;}

int find(int *fa, int x) {return x == fa[x] ? x : fa[x] = find(fa, fa[x]);}

struct edge {int u, v;};

void merge(int *fa, int x, int y) {
    x = find(fa, x), y = find(fa, y);
    if(x != y) fa[x] = y;
}

queue<edge> q1, q2;

int main() {
#ifndef ONLINE_JUDGE
    freopen("D:\\Chrome Downloadings\\input.txt", "r", stdin);
    freopen("D:\\Chrome Downloadings\\output.txt", "w", stdout);
#endif
    cin >> n >> m;
    init(fa1), init(fa2);
    for(int i = 1; i <= m; ++i) {
        int op = rd, u = rd, v = rd;
        if(op == 1) merge(fa1, u, v), q2.push({u, v});
        else merge(fa2, u, v), q1.push({u, v});
        while(!q1.empty()) {
            if(find(fa1, q1.front().u) == find(fa1, q1.front().v)) q1.pop();
            else break;
        }
        while(!q2.empty()) {
            if(find(fa2, q2.front().u) == find(fa2, q2.front().v)) q2.pop();
            else break;
        }
        puts(q1.empty() && q2.empty() ? "A" : "B");
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值