您的位置:首页 > 其它

bzoj2654: tree(二分+最小生成树)

2017-12-19 20:46 357 查看
题目传送门

神题。

解法:

想了我一个小时就是想不出来怎么做。

上来看看硬做行不行好像不行。

想了想二分边权和。

还是不行。。

想了很久怎么做。想不出来。

%题解!!

哇神方法。

当所有白色的边都加上一个东西的时候。

那么对于最后的方案白色的边因为权大了所以势必要减少。

当所有白色的边都减去一个东西的时候。、

那么对于最后的方案白色的边因为权小了所以势必要增多。

所以就二分这个东西呀。

然后去跑最小生成树。

跑出来的结果如果白色边的条数>=need说明白色的多了。

那么我们让他的数目减少一点,那么增加的权就应该多一点。

所以往大的二分。

如果白色边的条数

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<queue>
using namespace std;
struct node {int x,y,c,t;}a[110000];int len;
bool cmp(node n1,node n2) {if(n1.c==n2.c)return n1.t<n2.t;return n1.c<n2.c;}
int fa[51000];int findfa(int x) {if(fa[x]!=x)fa[x]=findfa(fa[x]);return fa[x];}
int main() {
int n,m,K;scanf("%d%d%d",&n,&m,&K);int l=-101,r=101,mid,ans=0;
for(int i=1;i<=m;i++){scanf("%d%d%d%d",&a[i].x,&a[i].y,&a[i].c,&a[i].t);a[i].x++;a[i].y++;}
while(l<=r) {
mid=(l+r)/2;for(int i=1;i<=m;i++)if(a[i].t==0)a[i].c+=mid;
sort(a+1,a+1+m,cmp);int t=0,sum=0,k=0;
for(int i=1;i<=n;i++)fa[i]=i;
for(int i=1;i<=m;i++) {
int xx=findfa(a[i].x),yy=findfa(a[i].y);
if(xx!=yy) {fa[xx]=yy;t++;sum+=a[i].c;if(a[i].t==0)k++;if(t==n-1)break;}
}for(int i=1;i<=m;i++)if(a[i].t==0)a[i].c-=mid;
if(k>=K) {l=mid+1,ans=sum-K*mid;}
else r=mid-1;
}
printf("%d\n",ans);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: