问题描述
克拉克是一名人格分裂患者。某一天克拉克变成了一名图论研究者。 他学习了最小生成树的几个算法,于是突发奇想,想做一个位运算and的最大生成树。 一棵生成树是由n−1条边组成的,且n个点两两可达。一棵生成树的大小等于所有在生成树上的边的权值经过位运算and后得到的数。 现在他想找出最大的生成树。
输入描述
第一行是一个整数T(1≤T≤5),表示数据组数。 每组数据第一行是两个整数n,m(1≤n,m≤300000),分别表示点个数和边个数。其中n,m>100000的数据最多一组。 接下来m行,每行3个整数x,y,w(1≤x,y≤n,0≤w≤109),表示x,y之间有一条大小为w的边。
输出描述
每组数据输出一行一个数,表示答案。若不存在生成树,输出0。
输入样例
1 4 5 1 2 5 1 3 3 1 4 2 2 3 1 3 4 7
输出样例
1
根据2进制一位一位往下做,找到符合的生成树#include<cstdio> #include<cstring> #include<cmath> #include<queue> #include<vector> #include<iostream> #include<algorithm> #include<bitset> #include<functional> using namespace std; typedef unsigned long long ull; typedef long long LL; const int maxn = 3e5 + 10; const int mod = 1e9 + 7; int T, n, m, fa[maxn], ans; struct point { int x, y, w; void read(){ scanf("%d%d%d", &x, &y, &w); } bool operator <(const point&a)const { return w > a.w; } }a[maxn]; int get(int x) { return fa[x] == x ? x : fa[x] = get(fa[x]); } int main() { scanf("%d", &T); while (T--) { cin >> n >> m; for (int i = 0; i < m; i++) a[i].read(); sort(a, a + m); ans = 0; for (int i = 29; i >= 0; i--) { int cnt = n - 1; for (int j = 1; j <= n; j++) fa[j] = j; for (int j = 0; j < m&&cnt; j++) { if (a[j].w < (1 << i)) break; if (a[j].w & (1 << i)) { int fx = get(a[j].x), fy = get(a[j].y); if (fx == fy) continue; fa[fx] = fy; cnt--; } } if (!cnt) { ans |= (1 << i); for (int j = 0; j < m; j++) { if (a[j].w < (1 << i)) break; if (a[j].w & (1 << i)) a[cnt++] = a[j]; } m = cnt; } } printf("%d\n", ans); } return 0; }