题解 ybt 1491:Tree | P2619 [国家集训队2]Tree I

ybt
luogu

分析

毒瘤题
裸的最小生成树显然是无法顾及颜色的,但是可以考虑给每条白边加权,显而易见,权值越小(可以小于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;
}
posted @ 2019-08-24 11:33  G_A_TS  阅读(635)  评论(1编辑  收藏  举报