BZOJ 2654: tree

Time Limit: 30 Sec  Memory Limit: 512 MB
Submit: 3344  Solved: 1425
[Submit][Status][Discuss]

Description

给你一个无向带权连通图,每条边是黑色或白色。让你求一棵最小权的恰好有need条白色边的生成树。
题目保证有解。

Input

第一行V,E,need分别表示点数,边数和需要的白色边数。
接下来E行,每行s,t,c,col表示这边的端点(点从0开始标号),边权,颜色(0白色1黑色)。

Output

一行表示所求生成树的边权和。
V<=50000,E<=100000,所有数据边权为[1,100]中的正整数。

Sample Input

2 2 1
0 1 1 1
0 1 2 0

Sample Output

2

HINT

原数据出错,现已更新 by liutian,但未重测---2016.6.24

Source


HOME Back

 

题解:

  这个题目,我们可以先二分一下给白边所加上的权值,因为我们只需要need条边,所以如果大于need,就需要使mid变大,所以l=mid+1,小于need就相反,但是对答案进行更新的时是在加白边总数大于(tmp)>=mid的时候,因为等于肯定可以,然后考虑如果加上mid   tmp>need但加上mid+1, tmp<need的情况,因为我们是在权值相等的情况下优先加入白边,所以可以将一些白边换成黑边.

 

代码:

  

/**************************************************************
    Problem: 2654
    User: 1796681012
    Language: C++
    Result: Accepted
    Time:3052 ms
    Memory:3248 kb
****************************************************************/
 
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <iostream>
#define MAXN 100100
using namespace std;
int fa[MAXN];
struct edge{
    int from,to,quan,id;
    void read(){
        scanf("%d%d%d%d",&from,&to,&quan,&id);from++,to++;
    }
}a[MAXN];
int ans,tmp=0,n,m,need,tot;
 
bool cmp(edge x,edge y){
    if(x.quan==y.quan) return x.id<y.id;
    return x.quan<y.quan;
}
 
int find(int now){
    if(fa[now]!=now) fa[now]=find(fa[now]);
    return fa[now];
}
 
void work(){
    tmp=0,tot=0;int hh=0;
    sort(a+1,a+m+1,cmp);
    for(int i=1;i<=m;i++){
        int x=a[i].from,y=a[i].to;int fax=find(x),fay=find(y);
        if(fax!=fay){
            fa[fax]=fay;
            tot+=a[i].quan;hh++;
            if(a[i].id==0) tmp++;
        }
        if(hh==n-1) break;
    }
}
 
int main()
{
    scanf("%d%d%d",&n,&m,&need);
    for(int i=1;i<=m;i++) a[i].read();
    int l=-105,r=105,mid;
    while(l<=r){
        mid=(l+r)/2;
        for(int i=1;i<=n;i++) fa[i]=i;
        for(int i=1;i<=m;i++) if(a[i].id==0) a[i].quan+=mid;
        work();
        if(tmp>=need) ans=tot-need*mid,l=mid+1;
        else r=mid-1;
        for(int i=1;i<=m;i++) if(a[i].id==0) a[i].quan-=mid;
    }
    printf("%d",ans);
    return 0;
}

 

posted @ 2018-08-23 22:12  人间失格—太宰治  阅读(109)  评论(0编辑  收藏  举报