P2619 [国家集训队]Tree I
二分答案。
考虑边肯定还是根据边权从小到大加入。
显然我们不能先加一堆白边。
但是我们可以通过白边的边权控制加入最小生成树的白边数量。
那么数量满足单调性可以二分。
#include<bits/stdc++.h>
using namespace std;
#define orz cout<<"lytcltcltcltcltcltcl"<<endl
inline int r(){int s=0,k=1;char c=getchar();while(!isdigit(c)){if(c=='-')k=-1;c=getchar();}while(isdigit(c)){s=s*10+c-'0';c=getchar();}return s*k;}
int n,m,need,tot,fa[1000001];
struct node
{
int from,to,dis,col;
}a[1000001];
bool cmp(node x,node y)
{
if(x.dis==y.dis)return x.col<y.col;
return x.dis<y.dis;
}
int father(int x)
{
if(fa[x]!=x)fa[x]=father(fa[x]);
return fa[x];
}
bool check(int x)
{
tot=0;
int now=0,whi=0;
for(int i=1;i<=m;i++)
if(a[i].col==0)a[i].dis+=x;
sort(a+1,a+m+1,cmp);
for(int i=1;i<=n;i++)fa[i]=i;
for(int i=1;i<=m;i++)
{
int x=a[i].from,y=a[i].to;
int fax=father(x),fay=father(y);
if(fax==fay)continue;
fa[fax]=fay;
tot+=a[i].dis;
if(a[i].col==0)whi++;
now++;
if(now==n-1)break;
}
for(int i=1;i<=m;i++)
if(a[i].col==0)a[i].dis-=x;
if(whi>=need)return 1;
return 0;
}
int main()
{
n=r();m=r();need=r();
for(int i=1;i<=m;i++)
{
a[i].from=r()+1;
a[i].to=r()+1;
a[i].dis=r();
a[i].col=r();
}
int l=-200,r=200,ans1=0,ans2=0;
while(l<=r)
{
// cout<<l<<" "<<r<<endl;
int mid=(l+r)/2;
if(check(mid))l=mid+1,ans1=mid,ans2=tot;//太多
else r=mid-1;
}
cout<<ans2-ans1*need;
}
本文来自博客园,作者:lei_yu,转载请注明原文链接:https://www.cnblogs.com/lytql/p/15224100.html