zoukankan      html  css  js  c++  java
  • 【BZOJ2654】tree 二分+最小生成树

    【BZOJ2654】tree

    Description

    给你一个无向带权连通图,每条边是黑色或白色。让你求一棵最小权的恰好有need条白色边的生成树。
    题目保证有解。

    Input

    第一行V,E,need分别表示点数,边数和需要的白色边数。
    接下来E行,每行s,t,c,col表示这边的端点(点从0开始标号),边权,颜色(0白色1黑色)。

    Output

    一行表示所求生成树的边权和。
    V<=50000,E<=100000,所有数据边权为[1,100]中的正整数。

    Sample Input

    2 2 1
    0 1 1 1
    0 1 2 0

    Sample Output

    2

    题解:又是一种奇奇怪怪的做法~

    如果我们给所有白色边增加边权,那么所选的白色边一定越来越少(反之同理)。所以我们二分给白色边增加多少边权,跑kruskal,最后再将增加的边权减去即可。

    但是你可能怀疑二分的正确性?即如果给白色边边权加上mid,则所选白色边>need,如果加上mid+1,则所选白色边<need。解决方法是,在排序的时候,我们将白色边放在相同长度的黑色边之前。这样,因为mid+1时白边<mid,所以一定有若干=mid的黑边。在mid时,我们多选的白边就可以被黑边替换掉。所以在最后统计答案的时候,只需要ans-=mid*need即可。

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    int n,m,nd,ans,sum,cnt,wt;
    struct edge
    {
    	int a,b,col,val;
    }p[100010];
    int f[50010];
    int rd()
    {
    	int ret=0,f=1;	char gc=getchar();
    	while(gc<'0'||gc>'9')	{if(gc=='-')f=-f;	gc=getchar();}
    	while(gc>='0'&&gc<='9')	ret=ret*10+gc-'0',gc=getchar();
    	return ret*f;
    }
    bool cmp(edge a,edge b)
    {
    	return (a.val==b.val)?(a.col<b.col):(a.val<b.val);
    }
    int find(int x)
    {
    	return (f[x]==x)?x:(f[x]=find(f[x]));
    }
    int solve(int x)
    {
    	int i,ra,rb,ret;
    	for(i=1;i<=m;i++)	if(!p[i].col)	p[i].val+=x;
    	sort(p+1,p+m+1,cmp);
    	sum=cnt=wt=0;
    	for(i=1;i<=n;i++)	f[i]=i;
    	for(i=1;i<=m;i++)
    	{
    		ra=find(p[i].a),rb=find(p[i].b);
    		if(ra!=rb)
    		{
    			cnt++,wt+=1-p[i].col,f[ra]=rb,sum+=p[i].val;
    			if(cnt==n-1)
    			{
    				if(wt>=nd)	ans=sum-x*nd,ret=1;
    				else	ret=0;
    			}
    		}
    	}
    	for(i=1;i<=m;i++)	if(!p[i].col)	p[i].val-=x;
    	return ret;
    }
    int main()
    {
    	int i,l=0,r=0,mid;
    	n=rd(),m=rd(),nd=rd();
    	for(i=1;i<=m;i++)	p[i].a=rd()+1,p[i].b=rd()+1,p[i].val=rd(),p[i].col=rd(),r=max(r,p[i].val+1);
    	l=-r;
    	while(l<r)
    	{
    		mid=l+r>>1;
    		if(solve(mid))	l=mid+1;
    		else	r=mid;
    	}
    	printf("%d",ans);
    	return 0;
    }
  • 相关阅读:
    harbor docker
    dns服务器
    k8s
    frps
    svn 搭建
    phpstrom 破解 转载https://www.jianshu.com/p/e71361b3bfee
    公开课
    k8s
    rsync各种备份
    定时任务
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/7189787.html
Copyright © 2011-2022 走看看