Codeforces Round #782 (Div. 2) AND-MEX Walk(位运算,并查集)

Codeforces Round #782 (Div. 2) AND-MEX Walk(位运算,并查集)

链接
题意:给出一副无向图,q次询问u,v之间的价值,价值的计算方法是 M E X ( w 1 , w 1 & w 2 , … , w 1 & w 2 & … & w k − 1 ) MEX({w1,w1\&w2,…,w1\&w2\&…\&wk−1}) MEX(w1,w1&w2,,w1&w2&&wk1),每条边可以经过多次。
思路:因为是 & \& &运算,首先对每一条边拆位,如果这一位的进制位是1,就连接两个点的这一位,而且其实只用判断连通性,用一个并查集就可以维护,然后需要证明的是答案只会是 0 / 1 / 2 0/1/2 0/1/2,对于答案是0的情况,就是说,u,v所有进制位的路径,只要有一个可以连通,就说明答案是0,因为这时,所有的这一位1都可以连通,都是大于0的数。答案是1时,就是说最低位有0,那这时,一定会出现一个0,mex就为1。假设为2以上的数字了,就说明 0 / 1 / 2 0/1/2 0/1/2都出现过,但是对于2的二进制位是 [ . . . , 1 , 0 ] [...,1,0] [...,1,0],1是 [ . . . , 0 , 1 ] [...,0,1] [...,0,1],此时最低位两个二进制位都出现过,往上的二进制位需要依赖这两位,并且 & \& &操作是一个不断变小的操作,所以3不成立时,往上也不会成立

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+10;
int fa[N][33];
int find(int n, int x) {return n == fa[n][x] ? n : fa[n][x] = find(fa[n][x], x);}
struct Node{int u, v, d;}e[N];
int can[N][33];

int main()
{
    int n, m;
    cin >> n >> m;
    for (int i = 1; i <= n; i++) {
        for (int j = 0; j <= 30; j++) {
            fa[i][j] = i;
        }
    }
    for (int i = 1; i <= m; i++) {
        int u, v, d;
        cin >> u >> v >> d;
        e[i] = {u, v, d};
        for (int j = 30; j >= 0; j--) {
            if (d & (1 << j)) {
                int x = find(u, j), y = find(v, j);
                if (x == y) continue;
                fa[x][j] = y;
            }
        }
    }
    for (int i = 1; i <= m; i++) {
        if (e[i].d % 2 == 0) {
            for (int j = 1; j <= 30; j++) {
                can[find(e[i].u, j)][j] = 1;
                can[find(e[i].v, j)][j] = 1;
            }
        }
    }
    int q;
    cin >> q;
    while (q--) {
        int u, v;
        cin >> u >> v;
        int ans = 2;
        for (int i = 30; i >= 0; i--) {
            int x = find(u, i), y = find(v, i);
            if (x == y) {ans = 0; break;}
        }
        if (ans != 0)
        for (int i = 1; i <= 30; i++) {
            if (can[find(u, i)][i]) {ans = 1; break;}
        }cout << ans << endl;
       // cout << endl;
    }
    return 0;
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值