题解 ybt 1491:Tree | P2619 [国家集训队2]Tree I
分析
毒瘤题
裸的最小生成树显然是无法顾及颜色的,但是可以考虑给每条白边加权,显而易见,权值越小(可以小于0),取的白边越多,反之越少
所以可以二分
Code
#include<bits/stdc++.h>
using namespace std;
struct edge
{
long long x,y,d,c;
}E[100010];
long long n,m,need,ans,fa[100010],tot,white,ANS;
int find(int x)
{
if(x==fa[x])
return x;
return fa[x]=find(fa[x]);
}
int cmp(edge a,edge b)
{
if(a.d==b.d)//!!!
return a.c<b.c;
return a.d<b.d;
}
int Kruskal(int x)
{
for(int i=0;i<=n;i++)
{
fa[i]=i;
}
for(int i=1;i<=m;i++)
{
if(!E[i].c)
E[i].d+=x;
}
sort(E+1,E+m+1,cmp);
ans=0,tot=0,white=0;
for(int i=1;i<=m;i++)
{
int f1=find(E[i].x),f2=find(E[i].y);
if(f1==f2)
continue;
fa[f1]=f2;
tot++;
ans+=E[i].d;
white+=(!E[i].c);
if(tot==n-1)
{
break;
}
}
for(int i=1;i<=m;i++)
{
if(!E[i].c)
E[i].d-=x;
}
if(white>=need)
return 1;
return 0;
}
int main()
{
//freopen("tree.in","r",stdin);
//freopen("tree.out","w",stdout);
cin>>n>>m>>need;
for(int i=1;i<=m;i++)
{
cin>>E[i].x>>E[i].y>>E[i].d>>E[i].c;
}
int l=-101,r=101;
while(l<=r)
{
int mid=(l+r)>>1;
if(Kruskal(mid))
{
l=mid+1;
ANS=ans-need*mid;
}
else
{
r=mid-1;
}
}
cout<<ANS;
}