也是比较神奇的一道题,我们先把白边都加一个权值,这样的话,每次最小生成树中白边都会减少,而且,这样肯定满足二分性质的。
不过,有一点需要注意的1是,排序是,如果权值相同,白边要排在前面。
#include<bits/stdc++.h>
#define N 100000
using namespace std;
struct line{
int x;
int y;
int val;
int col;
void read()
{
scanf("%d%d%d%d",&x,&y,&val,&col);
x++,y++;
}
};line A[N+1];
bool cmp(const line &A,const line &B)
{
if(A.val!=B.val) return A.val<B.val;
return A.col<B.col;
}
int m,n,ned;
int l,r,mid;
int f[N+1];
int tot,Ans,tmp;
int find(int x)
{
return x==f[x]?f[x]:f[x]=find(f[x]);
}
bool check(int x)
{
tot=0;
tmp=0;
for(int i=1;i<=n;i++)f[i]=i;
for(int i=1;i<=m;i++)
if(A[i].col==0)A[i].val+=x;
sort(A+1,A+m+1,cmp);
for(int i=1;i<=m;i++)
{
int fx=find(A[i].x),fy=find(A[i].y);
if(fx==fy)continue;
tot+=A[i].val;
if(A[i].col==0)tmp++;
f[fx]=fy;
}
for(int i=1;i<=m;i++)
if(A[i].col==0)A[i].val-=x;
return tmp>=ned;
}
int main()
{
scanf("%d%d%d",&n,&m,&ned);
for(int i=1;i<=m;i++)A[i].read();
l=-1e5,r=1e5;
while(l<=r)
{
mid=(l+r)/2;
if(check(mid))l=mid+1,Ans=tot-ned*mid;
else r=mid-1;
}
cout<<Ans;
return 0;
}