题目链接
题目大意:让你求一棵生成树,使这棵生成树所有的边通过与运算得到的值最大。
假设通过与运算得到的最大值为m,那么m每个二进制位上的1都应该与这棵树所有边的权值的二进制位对应位置的1相同。又因为进位制的性质,高位的数比所有低位的数之和还要大。所以我们可以通过从高到低来枚举二进制位,如果这个位上为1的边可以构成一棵生成树,那么就让这位为0的边都删掉,继续枚举下一位。
关于删边,链表是一个好方法,还有一个方法是通过一个数组来标记边,被标记的边就是被删掉的边。
//https://www.cnblogs.com/shuitiangong/
#include<set>
#include<map>
#include<list>
#include<stack>
#include<queue>
#include<cmath>
#include<cstdio>
#include<cctype>
#include<string>
#include<vector>
#include<climits>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define endl '
'
#define rtl rt<<1
#define rtr rt<<1|1
#define lson rt<<1, l, mid
#define rson rt<<1|1, mid+1, r
#define zero(a) memset(a, 0, sizeof(a))
#define INF(a) memset(a, 0x3f, sizeof(a))
#define IOS ios::sync_with_stdio(false)
#define _test printf("==================================================
")
using namespace std;
typedef long long ll;
typedef pair<int, int> P;
typedef pair<ll, ll> P2;
const double pi = acos(-1.0);
const double eps = 1e-7;
const ll MOD = 1000000009;
const int INF = 0x3f3f3f3f;
const int maxn = 3e5+10;
struct Edge {
int u, v; ll w;
bool operator < (const Edge &a) const {
return w > a.w;
}
} edge[maxn];
int n, m, p[maxn]; ll ans; bool del[maxn];
int find(int root) {
int son = root, tmp;
while(root != p[root]) root = p[root];
while(son != root) {
tmp = p[son];
p[son] = root;
son = tmp;
}
return root;
}
void kruskal(ll num) {
int s = 0;
for (int i = 0; i<=n; ++i) p[i] = i;
for (int i = 0; i<m; ++i)
if (!del[i] && (edge[i].w & num) && find(p[edge[i].u]) != find(p[edge[i].v])) {
++s;
p[find(edge[i].u)] = find(edge[i].v);
}
if (s == n-1) {
for (int i = 0; i<m; ++i)
if (~edge[i].w&num) del[i] = true;
ans |= num;
}
}
int main(void) {
int t;
scanf("%d", &t);
while(t--) {
scanf("%d%d", &n, &m);
for (int i = 0; i<m; ++i)
scanf("%d%d%lld", &edge[i].u, &edge[i].v, &edge[i].w);
sort(edge, edge+m);
ans = 0;
for (ll i = 32; i>=0; --i) {
ll tmp = 1LL << i;
kruskal(tmp);
}
printf("%lld
", ans);
memset(del, 0, sizeof(del[0])*(n+5));
}
return 0;
}