tree陈立杰
简单的kruskal不能保证白边个数,那么我们队百变统一加上一个权值,这样来控制白边的个数,也并不改变白边内部相对关系,二分判断加入的权值,如果num==need,用此时的sum-need*x(二分的权值)
也有可能出现一种情况,mid时白边个数太多,mid+1时白边个数太少,这样是因为mid时白边黑边权值相同的太多,这时我们只需要按颜色为第二关键字排序,保证相同权值下白边先被选中,二分时对于num>=need的更新答案
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define maxn 100005 using namespace std; int n,m,need; int sum,ans; struct edge { int s,t,w,col; }b[maxn],a[maxn]; int fa[maxn]; inline int read() { int x=0;char ch=getchar(); while(ch<'0'||ch>'9') ch=getchar(); while(ch>='0'&&ch<='9') {x=x*10+ch-'0';ch=getchar();} return x; } int cmp(const edge &a,const edge &b) { return a.w==b.w ? a.col<b.col : a.w<b.w; } int find(int x) { if(fa[x]!=x) fa[x]=find(fa[x]); return fa[x]; } int check(int x) { // printf("%d\n",x); memcpy(a,b,sizeof(b)); for(int i=0;i<=n;i++) fa[i]=i; for(int i=1;i<=m;i++) if(a[i].col==0) a[i].w+=x; sort(a+1,a+m+1,cmp); sum=0; int white_num=0,num=0; for(int i=1;i<=m;i++) { int fx=find(a[i].s); int fy=find(a[i].t); if(fx!=fy){ fa[fx]=fy; num++; sum+=a[i].w; if(a[i].col==0) white_num++; } if(num==n-1) break; } if(white_num==need) return 1; if(white_num>need) return 2; else return 0; } void erfen(int l,int r) { ans=0x7fffffff; while(l<=r){ int mid=(l+r)/2; int t=check(mid); if(t==1){ ans=sum-mid*need; break; } if(t==2){ ans=sum-mid*need; l=mid+1; } else r=mid-1; } } int main() { //freopen("in.txt","r",stdin); freopen("nt2012_tree.in","r",stdin); freopen("nt2012_tree.out","w",stdout); n=read();m=read();need=read(); for(int i=1;i<=m;i++){ b[i].s=read();b[i].t=read();b[i].w=read();b[i].col=read(); } erfen(-100,100); printf("%d\n",ans); //while(1); return 0; }