[BZOJ2654] tree

本文介绍了一种使用二分法寻找特定数量白色边的最小生成树的方法。通过调整白色边的权重,并利用二分搜索特性,可以高效地解决这一问题。文中还提供了一段示例代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

传送门

http://www.lydsy.com/JudgeOnline/problem.php?id=2654

题目大意

给定一些分为黑白两种的边,询问满足包含t条白边的最小生成树

题解

ORZ cls
如果我们想尽可能的多的白边我们要将白边权值加一个很大的负数
如果我们想尽可能的少的白边我们要将白边权值加一个很大的正数
这个是满足二分的性质的~
所以二分加的权值求最小生成树
注意排序时权值相同白边先行
有一个也可以用相同思想做的题[BZOJ3675] [Apio2014]序列分割

const
    maxn=50050;
    maxm=100050;
var
    x:array[0..maxm,1..4]of longint;
    fa:array[0..maxn]of longint;
    i,j,k:longint;
    n,m,t,l,r,mid,ans,sum:longint;
procedure sort(l,r:longint);
var i,j,a,b,c,d:longint;
begin
    i:=l; j:=r; a:=x[(l+r)div 2,3]; d:=x[(l+r)div 2,4];
    repeat
        while (x[i,3]<a)or((a=x[i,3])and(d>x[i,4])) do inc(i);
        while (a<x[j,3])or((a=x[j,3])and(d<x[j,4])) do dec(j);
        if not(i>j) then
        begin
            c:=1; b:=x[i,c]; x[i,c]:=x[j,c]; x[j,c]:=b;
            c:=2; b:=x[i,c]; x[i,c]:=x[j,c]; x[j,c]:=b;
            c:=3; b:=x[i,c]; x[i,c]:=x[j,c]; x[j,c]:=b;
            c:=4; b:=x[i,c]; x[i,c]:=x[j,c]; x[j,c]:=b;
            inc(i); dec(j);
        end;
    until i>j;
    if l<j then sort(l,j);
    if i<r then sort(i,r);
end;

function get(a:longint):longint;
begin
    if fa[a]=a then exit(a);
    fa[a]:=get(fa[a]);
    exit(fa[a]);
end;

function check(a:longint):longint;
var i,tot,b,c:longint;
begin
    for i:=1 to m do
        if x[i,4]=0 then inc(x[i,3],a);
    for i:=1 to n do
        fa[i]:=i;
    sort(1,m);
    tot:=0; sum:=0;
    for i:=1 to m do
        begin
            b:=get(x[i,1]); c:=get(x[i,2]);
            if b=c then continue;
            fa[b]:=c;
            inc(sum,x[i,3]);
            if x[i,4]=0 then inc(tot);
        end;
    for i:=1 to m do
        if x[i,4]=0 then dec(x[i,3],a);
    exit(tot);
end;

begin
    randomize;
    readln(n,m,t); ans:=0; sum:=0;
    for i:=1 to m do
        begin
            readln(x[i,1],x[i,2],x[i,3],x[i,4]);
            inc(x[i,1]); inc(x[i,2]);
        end;
    l:=-105; r:=105;
    while l<=r do
        begin
            mid:=(l+r)div 2;
            if check(mid)<t
            then r:=mid-1
            else begin ans:=sum-t*mid; l:=mid+1; end;
        end;
    writeln(ans);
end.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值