Orz hzwer
给白色边都加上一个值,做mst会使得选取的白边数量减少,所以可以二分它
跟DP枚举斜率是一个道理
#include<cstdio>
#include<cstdlib>
#include<algorithm>
using namespace std;
inline char nc()
{
static char buf[100000],*p1=buf,*p2=buf;
if (p1==p2) { p2=(p1=buf)+fread(buf,1,100000,stdin); if (p1==p2) return EOF; }
return *p1++;
}
inline void read(int &x)
{
char c=nc(),b=1;
for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}
const int N=50005;
const int M=100005;
struct edge{
int u,v,w,f;
bool operator < (const edge &B) const{
return w==B.w?f<B.f:w<B.w;
}
}E[M];
int n,m,need;
namespace TSet{
int fat[N],rank[N];
inline void init(int n){
for (int i=1;i<=n;i++) fat[i]=i,rank[i]=0;
}
inline int Fat(int u){
return fat[u]==u?u:fat[u]=Fat(fat[u]);
}
inline bool Union(int x,int y){
x=Fat(x); y=Fat(y); if (x==y) return 0;
if (rank[x]>rank[y]) swap(x,y);
if (rank[x]==rank[y]) rank[y]++;
fat[x]=y; return 1;
}
}
int sum=0,cnt=0,ans;
inline bool check(int mid){
using namespace TSet;
for (int i=1;i<=m;i++) if (!E[i].f) E[i].w+=mid;
sort(E+1,E+m+1); init(n); sum=cnt=0;
for (int i=1;i<=m;i++)
if (Union(E[i].u,E[i].v))
{
sum+=E[i].w;
if (!E[i].f) cnt++;
}
sum-=need*mid;
for (int i=1;i<=m;i++) if (!E[i].f) E[i].w-=mid;
return cnt<need;
}
int main()
{
read(n); read(m); read(need);
for (int i=1;i<=m;i++)
read(E[i].u),read(E[i].v),read(E[i].w),read(E[i].f),E[i].u++,E[i].v++;
int L=-105,R=105,MID;
while (L<=R)
if (check(MID=(L+R)>>1))
R=MID-1;
else
L=MID+1,ans=sum;
printf("%d\n",ans);
return 0;
}