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&…&wk−1),每条边可以经过多次。
思路:因为是
&
\&
&运算,首先对每一条边拆位,如果这一位的进制位是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;
}