bzoj 2654 tree

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2654

题解:

  若给每条白边加一个权值x,会使得选择白边的数量变少,即选择白边的数量f(x)单调递减,如此,二分x,使f(x)==need即可

 1 #include<cstdio>
 2 #include<algorithm>
 3 using namespace std;
 4 #define MAXN 50010
 5 #define MAXM 100010
 6 int father[MAXN],n,m,cnt,ans1,ans,need,u[MAXM],v[MAXM],val[MAXM];
 7 bool col[MAXM];
 8 struct node
 9 {
10     int u,v,val;
11     bool col;
12 }edge[MAXM];
13 void add(int a,int b,int c,int d,int i)
14 {
15     edge[i].u=a;
16     edge[i].v=b;
17     edge[i].val=c;
18     edge[i].col=d;
19 }
20 int cmp(node a,node b)
21 {
22     return a.val==b.val?a.col<b.col:a.val<b.val;//排序时尽量把白边排在前面 
23 }
24 int find(int x)
25 {
26     if(father[x]==x)return x;
27     else return father[x]=find(father[x]); 
28 }
29 bool Kruskal(int x)
30 {
31     ans1=cnt=0;//ans1为最小生成树权值和,cnt为所选白边数目 
32     for(int i=1;i<=n;i++)father[i]=i;
33     for(int i=1;i<=m;i++)
34     {
35         add(u[i],v[i],val[i],col[i],i);
36         if(!edge[i].col)edge[i].val+=x;
37     }
38     sort(edge+1,edge+m+1,cmp);
39     for(int i=1;i<=m;i++)
40     {
41         int a=find(edge[i].u);
42         int b=find(edge[i].v);
43         if(a==b)continue;
44         else
45         {
46             father[b]=a;
47             ans1+=edge[i].val;
48             if(!edge[i].col)cnt++;
49         }
50     }
51     return cnt>=need;
52 }
53 int main()
54 {
55     scanf("%d%d%d",&n,&m,&need);
56     for(int i=1;i<=m;i++)scanf("%d%d%d%d",&u[i],&v[i],&val[i],&col[i]);
57     int l=-100,r=100;
58     while(l<=r)
59     {
60         int mid=(l+r)/2;
61         if(Kruskal(mid))
62         {
63             l=mid+1;
64             ans=ans1-mid*cnt;//总权值减去多加上的白边边权 
65         }
66         else r=mid-1;
67     }
68     printf("%d",ans);
69     return 0;
70 }
原文地址:https://www.cnblogs.com/xqmmcqs/p/5965755.html