tree陈立杰

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

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

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxn 100005
using 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;
}


posted @ 2017-08-15 06:19  HunterxHunterl  阅读(223)  评论(0编辑  收藏  举报