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; }