bzoj2654
给白色边都加上一个值,做kruskal会使得选取的白边数量减少,二分它
#include<cstdio> #include<cctype> #include<algorithm> using namespace std; struct data{int u,v,w,col;}edge[100002],e[100002]; int n,m,ned,cnt,fa[100002]; unsigned int sumv,ans; inline void read(int &x){ char ch=getchar();x=0;int f=1; while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();} while(isdigit(ch)){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();} x*=f; } bool operator<(data a,data b){ return a.w==b.w?a.col<b.col:a.w<b.w; } int findfa(int x){ if(fa[x]==x)return x;return fa[x]=findfa(fa[x]); } bool check(int x){ sumv=cnt=0; for(int i=1;i<=n;i++)fa[i]=i; for(int i=1;i<=m;i++){e[i]=edge[i];if(!e[i].col)e[i].w+=x;} sort(e+1,e+m+1); for(int i=1;i<=m;i++){ int p=findfa(edge[i].u),q=findfa(edge[i].v); if(p!=q){ fa[p]=q; sumv+=e[i].w; if(!e[i].col)cnt++; } } return cnt>=ned; } int main(){ read(n);read(m);read(ned); for(int i=1;i<=m;i++){ read(edge[i].u);read(edge[i].v);read(edge[i].w);read(edge[i].col); edge[i].u++;edge[i].v++; } int l=-102,r=102; while(l<=r){ int mid=(l+r)>>1; if(check(mid)){l=mid+1;ans=sumv-ned*mid;}else r=mid-1; } printf("%d",ans); }