【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;
}
时间: 2024-12-16 14:01:12

【BZOJ2654】tree 二分+最小生成树的相关文章

BZOJ 2654 tree 二分+最小生成树

题目大意 给出一些边,每个边有一个边权和颜色.现在要求出最小边权有need个白边的生成树.输出这个边权. 思路 在白边上加一个权值,这样就可以人为的改变白边出现在最小生成树.这个东西显然可以二分.之后取一下最小值就可以了. CODE #define _CRT_SECURE_NO_WARNINGS #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #def

hdu4786 Fibonacci Tree (最小生成树)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4786 题意:给定图的n个点和m条双向边,告诉你每条边的权值.权值为1表示该边是白边,权值为0表示该边为黑边. 问能否找到一颗生成树,使生成树白边的个数刚好为fibonacci数.如果能构成输出yes,否则输出no. 思路:这里有一个点要知道.因为是0,1 tree.   最小生成树<=生成树的值<=最大生成树.  注意,这个区间的任意一个值都能取到. 但是如果不是0,1 tree,权值就不是任意可

hdu 2489 Minimal Ratio Tree 枚举+最小生成树

点的总数很小,直接枚举就好. #include <stdio.h> #include <string.h> #define N 20 #define inf 1000000 int mk[N],n,k,ans[N]; double low[N],val[N]; double map[N][N],MIN; double prim() { int i,j; double sum=0; double tot=0; for(i=1;i<=n;i++) low[i]=inf; int

Geeks : Kruskal’s Minimum Spanning Tree Algorithm 最小生成树

寻找图中最小连通的路径,图如下: 算法步骤: 1. Sort all the edges in non-decreasing order of their weight. 2. Pick the smallest edge. Check if it forms a cycle with the spanning tree formed so far. If cycle is not formed, include this edge. Else, discard it. 3. Repeat st

二分+最小生成树【bzoj2654】: tree

2654: tree 给你一个无向带权连通图,每条边是黑色或白色.让你求一棵最小权的恰好有need条白色边的生成树. 题目保证有解. 二分答案,然后跑最小生成树判断. 注意优先跑白色边. code: #include <iostream> #include <cstdio> #include <algorithm> using namespace std; const int wx=500017; inline int read(){ int sum=0,f=1; ch

Two Famous Companies 【二分+最小生成树】

Problem DescriptionIn China, there are two companies offering the Internet service for the people from all cities: China Telecom and China Unicom. They both are planning to build cables between cities. Obviously, the government wants to connect all t

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

【HDU 4408】Minimum Spanning Tree(最小生成树计数)

Problem Description XXX is very interested in algorithm. After learning the Prim algorithm and Kruskal algorithm of minimum spanning tree, XXX finds that there might be multiple solutions. Given an undirected weighted graph with n (1<=n<=100) vertex

UVALive 3662 Another Minimum Spanning Tree 曼哈顿最小生成树

题目链接:点击打开链接 题意: 给定二维平面的n个点坐标,问曼哈顿MST 的值. 模版题 #include <stdio.h> #include <iostream> #include <algorithm> #include <sstream> #include <stdlib.h> #include <string.h> #include <limits.h> #include <vector> #incl