#454. Minimum Or Spanning Tree

#454. Minimum Or Spanning Tree

题目描述

给出\(n\)个点, \(m\)条边的无向图, 每条边连接\(u,v\)两个端点,边权为\(w\), 求图的生成树的最小代价。

在这道题中, 我们定义一棵生成树的代价为他所有边的边权按位或得到的值。

输入格式

第一行两个数字 \(n\)\(m , n\) 表示点数,$m $表示图的边数。

接下来 \(m\) 行 , 每行三个整数 \(u,v,w\),表示点 \(u\) 和点\(v\) 之间存在一条边权为 \(w\) 的边。

输出格式

一行, 描述生成树的最小代价。

样例输入

5 7
4 2 7
2 5 8
3 4 2
3 2 1
2 4 2
4 1 2
1 2 2

样例输出

10

数据规模

所有数据保证 \(1≤u,v≤n≤2⋅10^5,n−1≤m≤4⋅10^5,1≤w≤10^9\)且至少存在一棵生成树。

题目分析

先假设\(ans\)为最大值,按位枚举看看当前位是否能为\(0\),把为\(0\)的放在一起,通过并查集检测是否构成联通图。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e5+7;
struct Edge {
	ll s,f;
	ll val;
};
inline int read(){
    int This=0,F=1; char ch=getchar();
    while(ch<'0'||ch>'9'){
        if(ch=='-') F=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9'){
        This=(This<<1)+(This<<3)+ch-'0';
        ch=getchar();
    }
    return This*F;
}
int fa[N];
inline int find(int x) {
	if(x==fa[x])
		return x;
	fa[x] = find(fa[x]);
	return fa[x];
}
inline void unoin(Edge x) {
	ll x_fa = find(x.s);
	ll y_fa = find(x.f);
	fa[x_fa] = y_fa;
}
inline bool check(int n) {
	int t = find(1);
	for(int i = 1 ; i <= n ; i++)
		if(find(i)!=t)
			return 0;
	return 1;
}
int main() {
//	freopen("input.txt","r",stdin);
//	freopen("output.txt","w",stdout);
	int n,m;
	scanf("%d%d",&n,&m);
	vector<Edge>e;
	for(int i = 1 ; i <= m ; i++) {
		ll s = read(),f= read(),val= read();
		e.push_back({s,f,val});
	}
	ll ans = (1ll<<32)-1;
	for(int i = 31 ; i>=0 ; i--) {
		ans -= (1ll<<i);
		vector<Edge>te;
		memset(fa,0,sizeof(fa));
		for(int i = 1 ; i <= n ; i++)
			fa[i] = i;
			
		for(int j = 0 ; j < e.size() ; j++) {
			if((e[j].val | ans) <= ans) { //希望筛出该位为0
				te.push_back(e[j]);
				unoin(e[j]);
			}
		}
		if(check(n))
			e = te;
		else ans += (1ll<<i);
	}
	printf("%lld",ans);
	return 0;
}
posted @ 2022-04-04 22:31  seekerHeron  阅读(66)  评论(0)    收藏  举报