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

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 }

 

posted @ 2016-07-15 20:47  ljh_2000  阅读(334)  评论(0编辑  收藏  举报