ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

题解 #10069.【国家集训队Tree】

2021-07-30 18:33:52  阅读:223  来源: 互联网

标签:int 题解 边权 10069 mid 生成 ans need 国家集训队


[国家集训队]Tree

题目大意:

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

solution:

考虑 \(\text{Kruskal}\) 的算法流程:每次取边权最小的边添到生成树里,所以为了让白色边进入生成树,我们可以将白色边的边权改变一下,但是改变多少呢?这个就可以用二分答案,再验证。单调性后面证。

具体操作如下:

  1. 二分出当前 \(mid\) ,把所有白色边的边权都减去 \(mid\) 。
  2. 构建最小生成树,记录被加入到生成树的白边的个数,同时记录答案。
  3. 若白边个数 \(\geq need\) 则统计答案:\(ans=res+need \times mid\)(把减去的 \(mid\) 加回来,共 \(need\) 条)。
  4. 把所有边权恢复,准备进行下一次二分。

单调性证明:

贪心的想,白色边的边权越小,则被加入到生成树的边数越多(显然),这样就满足了单调性。

证毕[滑稽]。

细节处理:

  • 这里的白边权有可能小导致生成树中白边过多,所以我们要增加权值,所以二分的左边界 \(l\) 要从 \(-101\) (\(< -100\) 的数),右边界 \(r\) 要取一个大于 \(100\) 的数。
  • 答案 \(ans\) 一定要用最小生成树的 \(res+\) 多减去的边权,不可直接用 \(res+=need \times mid\) 。

感性理解下:

若倒数第二次的二分答案验证成功,\(ans\) 被更新。而最后一次的验证失败,以后一种写法就会出问题:在求最小生成树时 \(ans\) 被清零,没法保存上次成功的答案,且此次答案不合法,从而丢了最优解。

代码
#include<cstdio>
#include<algorithm>
using namespace std;
const int N=5e4+5,M=1e5+5;
int n,m,need; 
struct B{
	int x,y,z,c;
}e[M];
inline bool cmp(B x,B y){
	if(x.z==y.z) return x.c<y.c;//这也要注意:若此时边权相等,优先选择白色的边
	else		 return x.z<y.z;
}
int fa[N];
inline int find(int s){
	return fa[s]==s?s:fa[s]=find(fa[s]);
}
int ans,res,num;
inline void kru(){
	sort(e+1,e+m+1,cmp);
	res=0,num=0;
	int cnt=0;
	for(int i=1;i<=m;i++){
		int x=e[i].x,y=e[i].y,z=e[i].z;
		int col=e[i].c;
		x=find(x),y=find(y);
		if(x!=y){
			fa[x]=y;
			if(!col) num++;//白色边数++
			res+=z;
			cnt++;
		}
		if(cnt==n-1) return ;
	}
}
int main(){
	scanf("%d%d%d",&n,&m,&need);
	for(int i=1;i<=m;i++){
		scanf("%d%d%d%d",&e[i].x,&e[i].y,&e[i].z,&e[i].c);
		e[i].x++,e[i].y++;
	}
	int l=-101,r=110;
	while(l<=r){
		int mid=l+r>>1;
		for(int i=1;i<=n+1;i++) fa[i]=i;
		for(int i=1;i<=m;i++) 
			if(!e[i].c) e[i].z-=mid;
		kru();
		if(num>=need) {//答案可行,减少白边数量
			r=mid-1;
			ans=res+need*mid;//注
		}
		else 		  l=mid+1;
		for(int i=1;i<=m;i++)
			if(!e[i].c) e[i].z+=mid;//恢复边权
	}
	printf("%d",ans);
	return 0;
}

End

标签:int,题解,边权,10069,mid,生成,ans,need,国家集训队
来源: https://www.cnblogs.com/TSZ-think/p/15080901.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有