bzoj2654 tree

来源:互联网 发布:cygwin和linux 编辑:程序博客网 时间:2024/05/22 06:29

题目

也是比较神奇的一道题,我们先把白边都加一个权值,这样的话,每次最小生成树中白边都会减少,而且,这样肯定满足二分性质的。

不过,有一点需要注意的1是,排序是,如果权值相同,白边要排在前面。

#include<bits/stdc++.h>#define N 100000using namespace std;struct line{    int x;    int y;    int val;    int col;    void read()    {        scanf("%d%d%d%d",&x,&y,&val,&col);        x++,y++;    }};line A[N+1];bool cmp(const line &A,const line &B){    if(A.val!=B.val) return A.val<B.val;    return A.col<B.col;}int m,n,ned;int l,r,mid;int f[N+1];int tot,Ans,tmp;int find(int x){    return x==f[x]?f[x]:f[x]=find(f[x]);}bool check(int x){    tot=0;    tmp=0;    for(int i=1;i<=n;i++)f[i]=i;    for(int i=1;i<=m;i++)        if(A[i].col==0)A[i].val+=x;    sort(A+1,A+m+1,cmp);    for(int i=1;i<=m;i++)    {        int fx=find(A[i].x),fy=find(A[i].y);        if(fx==fy)continue;        tot+=A[i].val;        if(A[i].col==0)tmp++;        f[fx]=fy;    }    for(int i=1;i<=m;i++)        if(A[i].col==0)A[i].val-=x;    return tmp>=ned;}int main(){    scanf("%d%d%d",&n,&m,&ned);    for(int i=1;i<=m;i++)A[i].read();    l=-1e5,r=1e5;    while(l<=r)    {        mid=(l+r)/2;        if(check(mid))l=mid+1,Ans=tot-ned*mid;        else r=mid-1;    }    cout<<Ans;    return 0;}