tree陈立杰

来源:互联网 发布:淘宝小二解封店铺 编辑:程序博客网 时间:2024/04/29 14:32

简单的kruskal不能保证白边个数,那么我们队百变统一加上一个权值,这样来控制白边的个数,也并不改变白边内部相对关系,二分判断加入的权值,如果num==need,用此时的sum-need*x(二分的权值)

也有可能出现一种情况,mid时白边个数太多,mid+1时白边个数太少,这样是因为mid时白边黑边权值相同的太多,这时我们只需要按颜色为第二关键字排序,保证相同权值下白边先被选中,二分时对于num>=need的更新答案

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#define maxn 100005using namespace std;int n,m,need;int sum,ans;struct edge{    int s,t,w,col;}b[maxn],a[maxn];int fa[maxn];inline int read(){       int x=0;char ch=getchar();       while(ch<'0'||ch>'9') ch=getchar();       while(ch>='0'&&ch<='9') {x=x*10+ch-'0';ch=getchar();}       return x;}int cmp(const edge &a,const edge &b){    return a.w==b.w ? a.col<b.col : a.w<b.w; }int find(int x){    if(fa[x]!=x) fa[x]=find(fa[x]);    return fa[x];}int check(int x){    // printf("%d\n",x);     memcpy(a,b,sizeof(b));     for(int i=0;i<=n;i++) fa[i]=i;     for(int i=1;i<=m;i++)     if(a[i].col==0) a[i].w+=x;     sort(a+1,a+m+1,cmp);     sum=0;     int white_num=0,num=0;     for(int i=1;i<=m;i++)     {         int fx=find(a[i].s);         int fy=find(a[i].t);             if(fx!=fy){             fa[fx]=fy; num++;             sum+=a[i].w;             if(a[i].col==0)  white_num++;         }         if(num==n-1) break;     }     if(white_num==need) return 1;     if(white_num>need) return 2;     else return 0;}void erfen(int l,int r){     ans=0x7fffffff;      while(l<=r){         int mid=(l+r)/2;         int t=check(mid);         if(t==1){ ans=sum-mid*need; break; }         if(t==2){ ans=sum-mid*need; l=mid+1; }         else  r=mid-1;     }}int main(){    //freopen("in.txt","r",stdin);    freopen("nt2012_tree.in","r",stdin);    freopen("nt2012_tree.out","w",stdout);    n=read();m=read();need=read();    for(int i=1;i<=m;i++){       b[i].s=read();b[i].t=read();b[i].w=read();b[i].col=read();    }    erfen(-100,100);    printf("%d\n",ans);    //while(1);    return 0;}