LOJ10069(BZOJ2654)

13 篇文章 0 订阅
7 篇文章 0 订阅

LOJ10069

我们考虑Kruscal,显然边权越小越早被考虑
所以白边的边权变小后,所能加进最小生成树的边数绝对不会变少(感性理解,有很大几率变多。。
所以我们就可以二分“每条白边的增量(可以为负)”
每次求出当前最小生成树后,更新的答案要减去need*mid
——如果有超过need条白边被用,超过的那部分一定能用黑边顶替,因为题目保证一定有恰好的解。。
(PS:边权这么小,计数排序,优个大 log l o g

#include<bits/stdc++.h>
#define gt() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++)
#define __R register
using namespace std;
static char buf[1000000],*p1=buf,*p2=buf;
const int maxn=(5e4)+5,maxE=(1e5)+5,maxp=305,P=100;
int n,m,k,S,Ans,fa[maxn],cnt[maxn];
struct ff{
    int x,y,w,col;
}E[maxE],tep;
int read(){
    int ret=0;char ch=gt();
    while(ch<'0'||ch>'9') ch=gt();
    while(ch>='0'&&ch<='9') ret=ret*10+ch-'0',ch=gt();
    return ret;
}
int tot,son[maxE],nxt[maxE],lnk[maxp];
void add_e(int x,int y){son[++tot]=y,nxt[tot]=lnk[x],lnk[x]=tot;}
int getfa(int x){return fa[x]==x?x:fa[x]=getfa(fa[x]);}
bool Kruscal(int x){
    memset(lnk,0,sizeof lnk),tot=S=0;
    for(__R int i=1;i<=n;i++) fa[i]=i,cnt[i]=1;
    for(__R int i=1;i<=m;i++) if(E[i].col) add_e(E[i].w+P,i);else add_e(E[i].w+x+P,i);
    int hsh=0;
    for(__R int i=1,fx,fy;i<=300;i++)
      for(__R int j=lnk[i];j;j=nxt[j])if((fx=getfa(E[son[j]].x))!=(fy=getfa(E[son[j]].y))){
        if(E[son[j]].col) S+=E[son[j]].w;else hsh++,S+=E[son[j]].w+x;
        if(cnt[fx]<cnt[fy]) cnt[fy]+=cnt[fx],fa[fx]=fy;else cnt[fx]+=cnt[fy],fa[fy]=fx;
      }
    return (hsh>=k);
}
int main(){
    n=read(),m=read(),k=read();
    for(__R int i=1,L=0,R=m+1;i<=m;i++){
        tep=(ff){read()+1,read()+1,read(),read()};
        if(tep.col) E[++L]=tep;else E[--R]=tep;
    }
    int L=-100,R=100,mid;
    while(L<=R){
        mid=L+R>>1;
        if(Kruscal(mid)) L=mid+1,Ans=S-k*mid;else R=mid-1;
    }
    printf("%d\n",Ans);
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值