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
HINT
原数据出错,现已更新 by liutian,但未重测---2016.6.24
正解:二分答案+最小生成树
解题报告:
今天LCF的分治题出了这道农boy题,完全不知道跟分治有什么关系。。。
题解太神,想通这么搞的目的之后就很简单了。
首先如果直接做,显然用的白边不一定是要求的值,如果边数多了,那么我们考虑如果所有的白边都增加一个值,显然白边数不会增加,应该会减少。这样就可以使我们确定答案选取了哪些白边。边数少了的话,也是一个道理。所以我们考虑二分答案,增加减少的边权必须在边权范围内(多了没意义)。
注意一下细节,相等情况下,先选白边,可以证明更优。我是蒟蒻,我不会证。
1 //It is made by jump~ 2 #include <iostream> 3 #include <cstdlib> 4 #include <cstring> 5 #include <cstdio> 6 #include <cmath> 7 #include <algorithm> 8 #include <ctime> 9 #include <vector> 10 #include <queue> 11 #include <map> 12 #include <set> 13 #ifdef WIN32 14 #define OT "%I64d" 15 #else 16 #define OT "%lld" 17 #endif 18 using namespace std; 19 typedef long long LL; 20 const int MAXN = 100011; 21 const int MAXM = 400011; 22 int n,m,allow; 23 int first[MAXN]; 24 int father[MAXN]; 25 int ecnt,cnt; 26 LL tot; 27 LL ans; 28 29 struct edge{ 30 int u,v,w; 31 int flag; 32 }e[MAXM]; 33 34 inline int getint() 35 { 36 int w=0,q=0; 37 char c=getchar(); 38 while((c<'0' || c>'9') && c!='-') c=getchar(); 39 if (c=='-') q=1, c=getchar(); 40 while (c>='0' && c<='9') w=w*10+c-'0', c=getchar(); 41 return q ? -w : w; 42 } 43 44 inline int find(int x){ 45 if(father[x]!=x) father[x]=find(father[x]); 46 return father[x]; 47 } 48 49 inline bool cmp(edge q,edge qq){ if(q.w==qq.w) return q.flag<qq.flag; return q.w<qq.w; } 50 51 inline bool check(int x){ 52 for(int i=1;i<=n;i++) father[i]=i; 53 for(int i=1;i<=m;i++) if(!e[i].flag) e[i].w+=x; 54 sort(e+1,e+m+1,cmp); 55 int r1,r2; cnt=0; tot=0; 56 for(int i=1;i<=m;i++) { 57 r1=find(e[i].u); r2=find(e[i].v); 58 if(r1!=r2) { 59 father[r2]=r1; 60 if(!e[i].flag) cnt++; 61 tot+=e[i].w; 62 } 63 } 64 for(int i=1;i<=m;i++) if(!e[i].flag) e[i].w-=x; 65 if(cnt>=allow) return true; 66 return false; 67 } 68 69 inline void work(){ 70 n=getint(); m=getint(); allow=getint(); 71 for(int i=1;i<=m;i++) { 72 e[i].u=getint(); e[i].v=getint(); e[i].w=getint(); e[i].flag=getint(); 73 } 74 int l=-1001,r=1001,mid; 75 while(l<=r) { 76 mid=(l+r)/2; 77 if(check(mid)) { 78 l=mid+1; ans=tot-mid*allow; 79 }else{ 80 r=mid-1; 81 } 82 } 83 printf(OT,ans); 84 } 85 86 int main() 87 { 88 work(); 89 return 0; 90 }