题目链接:
https://codeforces.com/problemset/problem/1624/G
题目大意:
一棵 \(spanning tree\) 的 \(ority\) 就是它所有边权的位或值,现在给出一个图,求出里面 \(spanning tree\) 的 \(ority\) 的最小值,\(spanning tree\) 就是一个无环的连通子图。
思路:
刚开始看到题目的时候,第一时间想到的是最小生成树,每次添加一条最小的边到已知集合中,但是这个最小不好判断。于是反过来考虑,从“避圈法”改为“破圈法”。
因为要求最小的位或值,所以我们可以枚举二进制的每一位,去除掉该位为 1 的边,剩下的如果是连通图,那么该位就可以去掉,通过这种方式去去掉边。
代码:
#include <bits/stdc++.h>
using namespace std;
#define LL long long
const int N = 2e5 + 10;
LL T = 1, n, m, fa[N];
struct node{
LL u, v, w;
}e[N];
LL find(LL x){
if (fa[x] == x) return x;
return fa[x] = find(fa[x]);
}
void join(LL a, LL b){
fa[find(b)] = find(a);
}
bool judge(LL x){
for (int i = 1; i <= n; i++)
fa[i] = i;
for (int i = 1; i <= m; i++){
if (e[i].w & x) continue;
join(e[i].u, e[i].v);
}
for (int i = 2; i <= n; i++)
if (find(fa[i]) != find(fa[i - 1]))
return false;
return true;
}
void solve(){
scanf("%lld%lld", &n, &m);
for (int i = 1; i <= m; i++)
scanf("%lld%lld%lld", &e[i].u, &e[i].v, &e[i].w);
LL res = 0;
for (int bit = 29; bit >= 0; bit--){
LL cur = res + (1LL << bit);
if (judge(cur))
res += (1LL << bit);
}
cout << (1LL << 30) - 1 - res << "\n";
}
int main(){
cin >> T;
while (T--)
solve();
return 0;
}