【洛谷P5633】最小度限制生成树

摘要:
思路假设我们直接计算最小生成树,此时,最小生成树上有一条边是连接点。当恰好有一条连接边时,设最小生成树权重之和为,则我们可以将其视为二维平面上的一个点。连接这些点后,必须有一个较低的凸壳。因为在仅仅删除黑边和添加白边的过程中,为了使生成树的权重尽可能小,必须选择差异最小的一个并首先添加。所以我们可以使用wqs二分法来解决这个问题。时间复杂度,其中是最大边权重。
题目

题目链接:https://www.luogu.com.cn/problem/P5633
给你一个有 (n) 个节点,(m) 条边的带权无向图,你需要求得一个生成树,使边权总和最小,且满足编号为 (s) 的节点正好连了 (k) 条边。
(nleq 5 imes 10^4,mleq 5 imes 10^5,kleq 100)

思路

假设我们直接求出了最小生成树,此时最小生成树上有 (t) 条边是连接 (s) 点的。不妨设 (t<k)
如果此时加入一条没被选择的连接 (s) 的边,必然会形成一个环,那么我们找到环上权值最大的不连接 (s) 的边删去。重复上述过程就可以得到一个有 (k) 条边连接 (s) 的生成树。
设恰好有 (i) 条连接 (s) 的边时最小生成树权值和为 (s_i),那么我们可以把 ((i,s_i)) 看做一个二维平面上的点。连接这些点之后必然是一个下凸壳。因为在刚刚删去黑边加入白边的过程中,为了让生成树权值尽量小,一定是选择差值最小的先加入。
于是就可以采用 wqs 二分解决这个问题了。
时间复杂度 (O(mlog mlog V)),其中 (V) 是边权最大值。

代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

const int N=50010,M=500010;
int n,m,s,k,cnt,maxd,father[N];
ll sum,ans;

struct edge
{
	int u,v,dis;
}e[M];

bool cmp(edge x,edge y)
{
	return x.dis<y.dis;
}

int find(int x)
{
	return x==father[x]?x:father[x]=find(father[x]);
}

void kruskal()
{
	sort(e+1,e+1+m,cmp);
	for (int i=1;i<=m;i++)
	{
		int x=find(e[i].u),y=find(e[i].v);
		if (x!=y)
		{
			if (e[i].u==s || e[i].v==s) cnt++;
			sum+=e[i].dis; father[x]=y; 
		}
	}
}

int main()
{
	scanf("%d%d%d%d",&n,&m,&s,&k);
	for (int i=1;i<=n;i++) father[i]=i;
	for (int i=1;i<=m;i++)
	{
		scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].dis);
		if (e[i].u!=s && e[i].v!=s) 
			father[find(e[i].u)]=find(e[i].v),cnt++;
		maxd=max(maxd,e[i].dis);
	}
	if (cnt+k<n-1) { cout<<"Impossible"; return 0; }
	int l=-maxd,r=maxd,mid;
	ans=-1;
	while (l<=r)
	{
		mid=(l+r)>>1;
		for (int i=1;i<=m;i++)
			if (e[i].u==s || e[i].v==s) e[i].dis+=mid;
		cnt=sum=0;
		for (int i=1;i<=n;i++) father[i]=i;
		kruskal();
		if (cnt>=k) l=mid+1,ans=sum-1LL*mid*k;
			else r=mid-1;
		for (int i=1;i<=m;i++)
			if (e[i].u==s || e[i].v==s) e[i].dis-=mid;
	}
	if (ans!=-1) cout<<ans;
		else cout<<"Impossible";
	return 0;
}

免责声明:文章转载自《【洛谷P5633】最小度限制生成树》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇Tomcat学习总结(5)——Tomcat容器管理安全的几种验证方式python处理csv文件问题解决贴下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

随便看看

JS事件 文本框内容改变事件(onchange)通过改变文本框的内容来触发onchange事件,同时执行被调用的程序。

以下代码显示,当用户更改文本框中的文本时,会弹出一个对话框“您更改了文本内容!”。运行结果:该任务补充了右侧编辑器的第13行。当文本框的内容发生更改时,将调用message()函数,并弹出对话框“您更改了文本内容!”。DOCTYPEHTML˃文本框内容更改事件functionmessage(){alert(“您更改了文本内容!”);}个人简介:请编写您的个人...

allure报告实现保存失败用例截图功能

allure中可以保存日志信息和截图日志allure能够自动识别。截图需要自己在添加allure方法。...

谷歌浏览器插件安装、VIP看视频、解除百度网盘限速

谷歌浏览器的插件主要由石油猴子获得。为了安装油猴,您需要先安装Google Access Assistant。utm_Source=chrome ntp图标建议使用几个视频下载插件https://jingyan.baidu.com/article/49711c61b19dd5fa441b7ccd.html两个插件“百度通用网盘助手”、“网盘直链下载助手”和一...

C# Task详解

1.任务线程池的优点与线程相比有很多优点,但线程池不方便使用。例如:◆ ThreadPool不支持线程取消、完成和失败通知等交互操作;◆ ThreadPool不支持线程执行顺序;在过去,如果开发人员想要实现上述功能,他们需要完成大量额外的工作。现在,FCL提供了一个更强大的概念:任务。任务基于线程池执行...

TCP UDP (转)

在互联网的早期,NCP协议用于主机之间的互连。该协议本身存在许多缺陷,例如:无法互连不同的主机,无法互连不同操作系统,并且没有纠错功能。为了改善这个缺点,Daniel提出了TCP/IP协议。现在几乎所有的操作系统都实现了TCP/IP协议栈。TCP/IP协议栈主要分为四层:应用层、传输层、网络层和数据链路层。每个层都有相应的协议。如下图所示,所谓的协议是双方之...

WindowsForm实现折叠菜单面板

在程序开发的过程中,有时候为了让我们程序的主要内容能够显示的区域更大,我们需要把一些面板折叠起来,今天就简单介绍一种菜单面板折叠的实现。首先,先用panel将构建出整体的页面布局,然后在菜单面板上添加上一个折叠按钮或者图片控件都可以,并将控件的Anchor属性成Top|Right,这样在页面折叠时,控件能够随着panel的宽度进行相对位置移动。private...