赞
踩
题解:本题最小生成树权值被定义为所有边权与的值。又因为我们只需要求出最终的权值就行了,不必关心中间过程。所以直接从最终权值res考虑,拆分成二进制后从高位到低位一位一位去看:
若当前位上为0的所有被边可以构成一个连通块,那么就从这个基础上继续考虑下一位(即当前位上为1的边就打个标记后面不考虑了);否则我们肯定要至少找出来一个当前位为1的边继续连直到构成一个连通的树位置(即这一位必须是1)。
AC代码:
#include <bits/stdc++.h> #define int long long using namespace std; const int N=1e6+5; int n,m; struct node{ int a,b,w; }e[N]; int p[N]; bool st[N]; int find(int x){ if(p[x]!=x) return p[x]=find(p[x]); return x; } bool check(int k){ for(int i=0;i<=n;i++) p[i]=i; for(int i=0;i<m;i++){ if(st[i]||e[i].w&(1LL<<k))continue; int a=e[i].a,b=e[i].b; int aa=find(a),bb=find(b); if(aa!=bb)p[aa]=bb; } for(int i=1;i<=n;i++){ if(find(1)!=find(i))return false; } return true; } void solve(){ cin>>n>>m; for(int i=0;i<m;i++){ int a,b,c; cin>>a>>b>>c; e[i]={a,b,c}; } for(int i=0;i<m;i++)st[i]=false; int res=0; for(int i=30;i>=0;i--){ if(check(i)){ for(int j=0;j<m;j++) if(e[j].w&(1<<i)) st[j]=true; } else res+=(1LL<<i); } cout<<res<<endl; } main(){ int T; cin>>T; while(T--) solve(); }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。