[模拟训练][bzoj2654]Tree

题目描述

传送门/bzoj2654

分析

考虑如何才能让白边显得更(不)重要,即在每条白边上(加上)减去一个值。
我们可以二分这个值,然后做最小生成树。统计在此最小生成树里有多少白边。
然后我们就可以找到一个合适的值,带这个权再做一次最小生成树。
在计算答案的时候把这些值补偿回去就做完了。


怎样保证正好k条白边呢?
先加k条最小的白边,再加k-n-1条黑边…….
不会这么简单!贪心肯定是不可以的
那么考虑曾经做过的一道网络流:统计最大流,并要求边数最少
当时是边权乘上一个极大值后加一直接上最大流
类比一下
不妨改变白边权(偏移量)使其最小生成树上正好有k条白边……
恩……二分应运而生。
notice:
一定要在最后把这些值补充回去,不能够在最小生成树统计答案时补偿答案,我也不知道为什么……

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
#define N 50100
int n,m,k,cnt=0,ans;
int fa[N];
struct Node{
    int u,v,w,d;
}e[N*4],s[N*4];
void add(int u,int v,int w,int d){
    s[++cnt].u=u;s[cnt].v=v;s[cnt].w=w;s[cnt].d=d;
}
int cmp(Node a,Node b){
    if(a.w==b.w) return a.d<b.d;
    return a.w<b.w;
}
int find(int x){
    return fa[x]==x?x:fa[x]=find(fa[x]);
}
int kruskal(int mid){
    int num=0,bb_num=0,x,y,w,d,tx,ty;ans=0;
    memcpy(e,s,sizeof(s));
    for(int i=1;i<=n;i++) fa[i]=i;
    for(int i=1;i<=m;i++)
        if(!e[i].d) e[i].w+=mid;
    sort(e+1,e+m+1,cmp);
    for(int i=1;i<=m;i++){
        x=e[i].u;y=e[i].v;w=e[i].w;d=e[i].d;
        tx=find(x);ty=find(y);
        if(tx!=ty){
            if(!d) bb_num++;
            fa[tx]=ty;
            ans+=w;
            num++;
        }
        if(num==n-1) break;
    }
    return bb_num;
}
int main(){
//  freopen("tree.in","r",stdin);
//  freopen("tree.out","w",stdout);
    scanf("%d%d%d",&n,&m,&k);
    int a,b,c,d;
    for(int i=1;i<=m;i++){
        scanf("%d%d%d%d",&a,&b,&c,&d);
        a++;b++;add(a,b,c,d);
    }
    int l=-101,r=101,mid,numb;
    while(l<r){
        mid=(l+r+1)/2;
        numb=kruskal(mid);
        if(numb>=k) l=mid;
        else r=mid-1;
    }
    kruskal(l);
    printf("%d",ans-k*l);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值