克拉克是一名人格分裂患者。某一天克拉克变成了一名图论研究者。
他学习了最小生成树的几个算法,于是突发奇想,想做一个位运算and的最大生成树。
一棵生成树是由n-1n−1条边组成的,且nn个点两两可达。一棵生成树的大小等于所有在生成树上的边的权值经过位运算and后得到的数。 现在他想找出最大的生成树。
第一行是一个整数T(1 \le T \le 5)T(1≤T≤5),表示数据组数。 每组数据第一行是两个整数n, m(1 \le n, m \le 300000)n,m(1≤n,m≤300000),分别表示点个数和边个数。其中n, m > 100000n,m>100000的数据最多一组。 接下来mm行,每行33个整数x, y, w(1 \le x, y \le n, 0 \le w \le 10^9)x,y,w(1≤x,y≤n,0≤w≤109),表示x, yx,y之间有一条大小为ww的边。
每组数据输出一行一个数,表示答案。若不存在生成树,输出00。
1 4 5 1 2 5 1 3 3 1 4 2 2 3 1 3 4 7
1
这是一道好题,可惜我太笨,比赛的时候没做出来,虽然并不难。。。
从大到小枚举位数i,如果能生成树,那么该位的生成树MST(i)一定是前一位+(1<<i),当然对树上所有的边还要满足MST(i)&w==MST(i).
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include<set> #define REP(i,a,b) for(int i=a;i<=b;i++) #define MS0(a) memset(a,0,sizeof(a)) using namespace std; typedef long long ll; const int maxn=1000100; const int INF=1e9+10; int n,m; struct Edge { int u,v; ll w; };Edge e[maxn]; int fa[maxn]; int u,v; ll w; int find(int x) { return fa[x]==x?x:fa[x]=find(fa[x]); } void solve(ll t,ll &ans) { REP(i,1,n) fa[i]=i; ans+=t; REP(i,1,m){ u=e[i].u,v=e[i].v,w=e[i].w; int x=find(u),y=find(v); if(x!=y&&((w&ans)==ans)) fa[x]=y; } int st=find(1); REP(i,2,n){ if(find(i)!=st){ ans-=t;return; } } } int main() { #ifndef ONLINE_JUDGE freopen("in.txt","r",stdin); #endif int T;cin>>T; while(T--){ scanf("%d%d",&n,&m); REP(i,1,m){ scanf("%d%d%I64d",&u,&v,&w); e[i]=(Edge){u,v,w}; } ll ans=0; for(int i=32;i>=0;i--){ solve(1LL<<i,ans); } printf("%I64d\n",ans); } return 0; }