BZOJ2654 tree (wqs二分)
Posted ynhnxn
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ2654 tree (wqs二分)相关的知识,希望对你有一定的参考价值。
题目描述
给你一个无向带权连通图,每条边是黑色或白色。让你求一棵最小权的恰好有need条白色边的生成树。
题目保证有解。
一个最小生成树问题,但是我们要选need条白边,我们用g(i)表示选取i条白边的最优方案(生成树的权值最小),那么可以大致猜出g(i)是关于i的一个下凸函数,可以发现斜率k是有单调性的,我们二分这个斜率k,相当于给每条白边的权值加上一个k,统计数量use,如果use>=need,说明k小了,要增大,同理,use<need,要减小k。
那么问题来了,如果说当前白边加上mid后,白边条数use>need了,如果加上mid+1后,use<need了要怎么办?
题目中说到了:保证有解,所以出现上述情况时一定有黑边==白边的边权
所以我们只需要把一条黑边换成白边就好,即我们排序时如果黑边权值等于白边,则白边优先。
#include<bits/stdc++.h> using namespace std; #define N 50001 #define M 100001 int n,m,k; struct node int u,v,w,c; e[M]; int use,sum,fa[N]; bool cmp(node a,node b) if(a.w!=b.w) return a.w<b.w; return a.c<b.c;//黑边白边权值一样,优先选白边 int find(int x) return fa[x]==x?x:fa[x]=find(fa[x]); void check(int x) for(int i=1;i<=m;i++) if(e[i].c==0) e[i].w+=x;//白边加权值 sort(e+1,e+m+1,cmp); for(int i=1;i<=n;i++) fa[i]=i; int now=0,fu,fv,j=1; use=0,sum=0; while(now!=n-1) fu=find(e[j].u);fv=find(e[j].v); if(fu!=fv) now++; fa[fu]=fv; if(e[j].c==0) ++use;//统计使用的白边数量 sum+=e[j].w; ++j; for(int i=1;i<=m;i++) if(e[i].c==0) e[i].w-=x;//还原 int main() scanf("%d%d%d",&n,&m,&k); for(int i=1;i<=m;i++) scanf("%d%d%d%d",&e[i].u,&e[i].v,&e[i].w,&e[i].c); ++e[i].u;++e[i].v;//题目是编号从0开始,要+1 int l=-101,r=101,mid,ans;//值域[1,100]; while(l<=r) mid=l+r>>1;check(mid); if(use>=k) ans=sum-k*mid; l=mid+1; else r=mid-1; cout<<ans; return 0;
以上是关于BZOJ2654 tree (wqs二分)的主要内容,如果未能解决你的问题,请参考以下文章