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 }