在本校神犇bright(点此近距离膜拜)的王(wei)之(bi)威(li)严(you)之下学了一手wqs(我七岁?我去送?)二分
然而我还不是很会。。。就不误人子弟讲这个算法了,大家可以去学一下
假如学会了的话,这里有个小细节,就是排序的时候相同长度颜色白的要放在颜色黑的前面,>=K记录答案
来想想边界?
假如这个决策mid令白边选少了,而mid+1令白边选多了,mid时因为我们先选白边,mid和mid+1的区别就只有在mid+1和白边长度相等黑边,换下来两者白边的差就是这些黑边的个数,那么必然在mid时候有足量的黑边来顶替白边使得白边数=need。
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; int n,m,K; struct edge{int x,y,d,c;}a[110000],e[110000]; bool cmp(edge e1,edge e2){return e1.d==e2.d?e1.c<e2.c:e1.d<e2.d;} int fa[51000]; int findfa(int x) { if(x==fa[x])return x; fa[x]=findfa(fa[x]);return fa[x]; } int check(int mid,int &d) { for(int i=1;i<=n;i++)fa[i]=i; for(int i=1;i<=m;i++) { e[i]=a[i]; if(a[i].c==0)e[i].d+=mid; } sort(e+1,e+m+1,cmp); int cnt=0,ret=0; for(int i=1;i<=m;i++) { int fx=findfa(e[i].x),fy=findfa(e[i].y); if(fx!=fy) { fa[fx]=fy; if(e[i].c==0)ret++; d+=e[i].d; cnt++;if(cnt==n-1)break; } } return ret; } int main() { freopen("a.in","r",stdin); freopen("a.out","w",stdout); scanf("%d%d%d",&n,&m,&K); for(int i=1;i<=m;i++) { scanf("%d%d%d%d",&a[i].x,&a[i].y,&a[i].d,&a[i].c); a[i].x++;a[i].y++; } int l=-100,r=100,ans; while(l<=r) { int mid=(l+r)>>1,d=0; int k=check(mid,d); if(k>=K) { l=mid+1; ans=d-mid*K; } else r=mid-1; } printf("%d ",ans); return 0; }