problem
solution
- 题意:生成树的代价为他所有边的边权按位或得到的值,求最小生成树
- 贪心,一般来说,求 按位与 和 按位或 的最大值都可以从高往低逐位的贪心处理
- 对于当前位 b 而言,若存在 n−1 条边的边权都不存在 b 且不构成环的话,那么我们可以把所有包含 b 的边都删除;若不足 n−1 条边满足之前的条件的话,则将 b 加入答案
//AC1
#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(0), cin.tie(0),cout.tie(0)
typedef long long LL;
const LL maxn = 1e6+10;
int fa[maxn+10];
void init(int n){for(int i = 0; i <= n; i++)fa[i]=i;}
int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}
void merge(int x, int y){x=find(x);y=find(y);if(x!=y)fa[x]=y;}
int count(int n){int cnt=0; for(int i = 1; i <= n; i++)if(fa[i]==i)cnt++;return cnt;}
struct node{int u, v, w; }e[maxn];
int vis[maxn];
int main(){
int n, m; cin>>n>>m;
for(int i = 1; i <= m; i++){
cin>>e[i].u>>e[i].v>>e[i].w;
}
int ans = 0;
for(int b = 29; b >= 0; b--){
init(n);
int cc = 1;
for(int i = 1; i <= m; i++){
if(vis[i])continue;
if((~e[i].w>>b) & 1){
if(find(e[i].u)!=find(e[i].v)){
merge(e[i].u, e[i].v);
cc++;
}
}
}
if(cc == n){
for(int i = 1; i <= m; i++){
if((~e[i].w>>b) & 1){
}else{
vis[i] = 1;
}
}
}else{
ans |= 1<<b;
}
}
cout<<ans<<"\n";
return 0;
}
//AC2
#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(0), cin.tie(0),cout.tie(0)
typedef long long LL;
const LL maxn = 1e6+10;
int fa[maxn+10];
void init(int n){for(int i = 1; i <= n; i++)fa[i]=i;}
int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}
void merge(int x, int y){x=find(x);y=find(y);if(x!=y)fa[x]=y;}
int count(int n){int cnt=0; for(int i = 1; i <= n; i++)if(fa[i]==i)cnt++;return cnt;}
tuple<int,int,int>e[maxn<<1];
int main(){
IOS;
int n, m; cin>>n>>m;
for(int i = 1; i <= m; i++){
cin>>get<0>(e[i])>>get<1>(e[i])>>get<2>(e[i]);
}
int k = 29;
int ans = (1<<k)-1;
for(int i = k-1; i >= 0; i--){
init(n);
int cc = n;
ans ^= (1<<i);
for(int j = 1; j <= m; j++){
if((get<2>(e[j])|ans)==ans && find(get<0>(e[j]))!=find(get<1>(e[j]))){
merge(get<0>(e[j]), get<1>(e[j]));
cc--;
}
}
ans ^= ((int)(cc!=1)<<i);
}
cout<<ans<<"\n";
return 0;
}