bzoj2654 tree 最小生成树+二分验证
2016-12-20 21:25
316 查看
给你一个无向带权连通图,每条边是黑色或白色。让你求一棵最小权的恰好有need条白色边的生成树。
因为随着白色边权值同时增大或同时减小,最小生成树中白色数量也会增大或减小,所以可以二分一个值Mid,白色边同时加上Mid,求生成树中白边数量。然后调整上下界。
因为随着白色边权值同时增大或同时减小,最小生成树中白色数量也会增大或减小,所以可以二分一个值Mid,白色边同时加上Mid,求生成树中白边数量。然后调整上下界。
#include<iostream> #include<cstdio> #include<algorithm> #define maxn 50005 using namespace std; struct E{ int f,t,d,c; void read() {scanf("%d%d%d%d",&f,&t,&d,&c);} }b[maxn<<1]; bool cmp(E A,E B) { if(A.d!=B.d) return A.d<B.d; return A.c<B.c; } int F[maxn]; int find(int x) {return F[x]==x?x:F[x]=find(F[x]);} int n,m,d; bool kul() { for(int i=0;i<=n;i++) F[i]=i; sort(b+1,b+m+1,cmp); int cnt=0,tot=0; for(int i=1;i<=m;i++) { int f=b[i].f,t=b[i].t; if(find(f)!=find(t)) { F[find(f)]=find(t);tot++; if(!b[i].c) cnt++; } } if(cnt>=d&&tot==n-1) return true; return false; } int main() { scanf("%d%d%d",&n,&m,&d); for(int i=1;i<=m;i++) b[i].read(); int l=-101,r=101; while(r-l>1) { int mid=(l+r)>>1; for(int i=1;i<=m;i++) if(!b[i].c)b[i].d+=mid; if(kul()) l=mid; else r=mid; for(int i=1;i<=m;i++) if(!b[i].c)b[i].d-=mid; } for(int i=1;i<=m;i++) if(!b[i].c) b[i].d+=l; sort(b+1,b+m+1,cmp); for(int i=0;i<=n;i++) F[i]=i; int ans=0; for(int i=1;i<=m;i++) { int f=b[i].f,t=b[i].t; if(find(f)!=find(t)) { F[find(f)]=find(t); ans+=b[i].d; } } ans-=d*l; cout<<ans; return 0; }
相关文章推荐
- bzoj2654 Tree 二分答案+最小生成树
- poj 2728 Desert King 二分+O(n^2)最小生成树验证
- [bzoj2654]tree 二分+最小生成树
- [bzoj2654][最小生成树][二分]tree
- 二分+最小生成树【bzoj2654】: tree
- BZOJ 2654 tree - 二分+最小生成树
- bzoj2654: tree(二分+最小生成树)
- 【二分+最小生成树】BZOJ2654[tree]题解
- bzoj 2654: tree (二分+最小生成树)
- BZOJ 2654: tree 最小生成树+二分
- 【BZOJ2654】tree 二分+最小生成树
- BZOJ2654 tree 【二分 + 最小生成树】
- 【bzoj2654】【tree】【二分+最小生成树】
- bzoj 2654: tree 二分+最小生成树
- 【bzoj2654】【二分+最小生成树】tree
- [bzoj2654]tree(二分+最小生成树)
- [bzoj2654]tree(最小生成树+二分)
- BZOJ 2654 tree(二分答案+最小生成树)
- <二分答案加验证||最小生成树>bzoj 1821 部落划分
- [国家集训队2012]Tree 最小生成树+二分