P2619 [国家集训队2]Tree I(最小生成树+二分)

P2619 [国家集训队2]Tree I

每次二分一个$x$,每条白边加上$x$,跑最小生成树

统计一下满足条件的最小值就好了。

to me:注意二分不要写挂

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int n,m,T,fa[50005],ans,tt;
struct edge{int f,t,v,c;}a[100005],b[100005];
inline bool cmp(edge A,edge B){return (A.v==B.v)?A.c<B.c:A.v<B.v;}
int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
int kruskal(){
    int re=0,k=n-1; tt=0;
    for(int i=1;i<=n;++i) fa[i]=i;
    sort(b+1,b+m+1,cmp);
    for(int i=1;k&&i<=m;++i){
        int r1=find(b[i].f),r2=find(b[i].t);
        if(r1!=r2) --k,re+=(b[i].c^1),tt+=b[i].v,fa[r1]=r2;
    }return re;
}
bool F(int x){
    for(int i=1;i<=m;++i) b[i]=a[i],b[i].v+=(b[i].c^1)*x;
    return kruskal()>=T;
}
int main(){
    scanf("%d%d%d",&n,&m,&T);
    for(int i=1;i<=m;++i)
        scanf("%d%d%d%d",&a[i].f,&a[i].t,&a[i].v,&a[i].c),++a[i].f,++a[i].t;
    int l=-100,r=100;
    while(l<=r){//注意边界是l<=r!
        int mid=(l+r)/2;
        if(F(mid)) ans=tt-T*mid,l=mid+1;
        else r=mid-1;
    }printf("%d",ans);
    return 0;
}

 

转载于:https://www.cnblogs.com/kafuuchino/p/10816571.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值