BZOJ2654:tree(最小生成树,二分)
Description
给你一个无向带权连通图,每条边是黑色或白色。让你求一棵最小权的恰好有need条白色边的生成树。
题目保证有解。
Input
第一行V,E,need分别表示点数,边数和需要的白色边数。
接下来E行,每行s,t,c,col表示这边的端点(点从0开始标号),边权,颜色(0白色1黑色)。
Output
一行表示所求生成树的边权和。
V<=50000,E<=100000,所有数据边权为[1,100]中的正整数。
Sample Input
2 2 1
0 1 1 1
0 1 2 0
0 1 1 1
0 1 2 0
Sample Output
2
Solution
二分加到白边上的值……加的值越大白边数越少,加的越小白边数越多。
比较函数写错真是gg……
Code
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #define N (200009) 5 using namespace std; 6 7 struct Edge 8 { 9 int u,v,l,c; 10 bool operator < (const Edge &a) const{return l<a.l || l==a.l && c<a.c;} 11 }V[N]; 12 int n,m,u,v,w,c,need,e0,e1,refun,wcnt,fa[N]; 13 14 int Find(int x){return x==fa[x]?x:fa[x]=Find(fa[x]);} 15 16 bool check(int x) 17 { 18 refun=0; wcnt=0; 19 for (int i=1; i<=n; ++i) fa[i]=i; 20 for (int i=1; i<=m; ++i) if (V[i].c==0) V[i].l+=x; 21 sort(V+1,V+m+1); 22 for (int i=1; i<=m; ++i) 23 { 24 int fx=Find(V[i].u), fy=Find(V[i].v); 25 if (fx!=fy) wcnt+=(V[i].c^1), fa[fx]=fy, refun+=V[i].l; 26 } 27 for (int i=1; i<=m; ++i) if (V[i].c==0) V[i].l-=x; 28 return wcnt>=need; 29 } 30 31 int main() 32 { 33 scanf("%d%d%d",&n,&m,&need); 34 for (int i=1; i<=m; ++i) 35 { 36 scanf("%d%d%d%d",&u,&v,&w,&c); u++; v++; 37 V[i]=(Edge){u,v,w,c}; 38 } 39 int l=-209,r=209,ans; 40 while (l<=r) 41 { 42 int mid=(l+r)>>1; 43 if (check(mid)) ans=mid,l=mid+1; 44 else r=mid-1; 45 } 46 check(ans); printf("%d\n",refun-need*ans); 47 }