【CF2021E】Digital Village(All Version)

news2024/12/25 16:28:11

题目

给你一张 n n n 个点 m m m 条边的无向图,有 p p p 个关键点。你需要选择 k k k 个点染黑,使得这 p p p 个关键点到这 k k k 个黑点的代价和最小。定义代价为两点之间边权最大的边的最小值。
你需要求出 k = 1,2,…,n 的所有答案

E1 n,m,p<=400
E2 n,m,p<=5000
E3 n,m,p<=2e5

传送门

E1 & E2

两点之间最大边权最小值让你想到了什么?最小生成树。
但是这玩意直接在最小生成树上也不好做啊。但是如果是 kruskal 重构树呢?
显然,两个点 ( u , v ) (u,v) (u,v) 之间的代价就是重构树上的 v a l l c a ( u , v ) val_{lca(u,v)} vallca(u,v)
这样我们就可以愉快的dp啦!

d p u , i dp_{u,i} dpu,i 为以 u u u 为根的子树,染黑了 i i i 个关键点的最小代价。
转移要讨论这棵树有没有染黑任何一个点,如果没有的话整棵树的代价就是 s i z × v a l siz\times val siz×val,其中 s i z siz siz 为子树内关键点的个数。
做个树上背包就行啦。时间复杂度 O ( n 2 ) O(n^2) O(n2)

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e6+7,inf=1e18,mod=998244353;
int n,m,k;
vector<bool> bz;
vector<int> val,fa,siz;
vector<vector<int>> e,dp;
int gf(int x)
{
	return x==fa[x]?x:fa[x]=gf(fa[x]);
}
void dfs(int u,int fa)
{
	dp[u].assign(1,inf);
	if(bz[u])
	{
		siz[u]=1;
		dp[u].push_back(0);
	}
	for(auto v:e[u])
	{
		if(v==fa) continue;
		dfs(v,u);
		vector<int> dpn(siz[u]+siz[v]+1,inf);
		for(int i=1; i<=siz[u]+siz[v]; i++)
		{
			for(int j=max(0ll,i-siz[u]); j<=min(i,siz[v]); j++)
			{
				if(j==0)
				{
					dpn[i]=min(dpn[i],dp[u][i-j]+val[u]*siz[v]);
				}
				else if(i==j)
				{
					dpn[i]=min(dpn[i],dp[v][j]+val[u]*siz[u]);
				}
				else
				{
					dpn[i]=min(dpn[i],dp[u][i-j]+dp[v][j]);
				}
			}
		}
		siz[u]+=siz[v];
		dp[u]=dpn;
	}
}
void O_o()
{
	cin>>n>>m>>k;
	bz.assign(2*n,0);
	for(int i=1; i<=k; i++)
	{
		int x;
		cin>>x;
		bz[x]=1;
	}
	vector<array<int,3>> edge;//l,x,y
	for(int i=1; i<=m; i++)
	{
		int x,y,l;
		cin>>x>>y>>l;
		edge.push_back({l,x,y});
	}
	sort(edge.begin(),edge.end());
	fa.assign(2*n,0);
	for(int i=1; i<=2*n; i++) fa[i]=i;
	int rt=n;
	e.assign(2*n,vector<int>());
	val.assign(2*n,0);
	for(auto [l,x,y]:edge)
	{
		int u=gf(x),v=gf(y);
		if(u==v) continue;
		rt++;
		fa[u]=rt;
		fa[v]=rt;
		val[rt]=l;
		e[rt].push_back(u);
		e[rt].push_back(v);
	}
	dp.assign(2*n,vector<int>());
	siz.assign(2*n,0);
	dfs(rt,0);
	for(int i=1; i<=min(k,n); i++)
		cout<<dp[rt][i]<<" ";
	for(int i=k+1; i<=n; i++)
		cout<<"0 ";
	cout<<"\n";
}
signed main()
{
	ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
	cout<<fixed<<setprecision(12);
	int T=1;
	cin>>T;
	while(T--)
	{
		O_o();
	}
}

这个树上背包似乎很难继续优化了呢。我们必须从题目更深的性质去思考问题。
在解决 E3 之前,我们不妨先看一下这道题:

CCPC2024 山东邀请赛 F

在这里插入图片描述
这是一道签到题。
可以发现,这个式子可以拆成 k k k 段后缀和之和,并且其中一段后缀和必须是整个序列。
所以直接把后缀和排个序,选出前 k − 1 k-1 k1 大的后缀和,再加上整个序列的和即可。

E3

在题目中,一个点都不染色是不合法的,代价应该为 i n f inf inf,但这不利于我们解题。
我们不妨假设他们每一条路径都经过了最大的那条边,也就是初始答案 a n s = s i z r t ∗ v a l r t ans=siz_{rt}*val_{rt} ans=sizrtvalrt
把样例的重构树画出来,观察一下染黑了一个叶子,对答案会有什么影响?
不太好看出来?由那道签到题的启发,给 v a l val val 做个树上差分试试?
可以发现,从叶子结点到根的那条路径上, v a l f a − v a l u val_{fa}-val_{u} valfavalu 的计算次数都被减少了 s i z u siz_u sizu
再染一个点试试?可以发现,从叶子结点,一直到已经被选择过的那条链为止, v a l f a − v a l u val_{fa}-val_{u} valfavalu 的计算次数都被减少了 s i z u siz_u sizu
问题就转换成了,你要在树上选出减少答案前 k k k 大,互不相交的链。
是不是很像树链剖分?
没错,我们把 ( v a l f a − v a l u ) ∗ s i z u (val_{fa}-val_{u})*siz_u (valfavalu)sizu 作为 ( u , f a u ) (u,fa_u) (u,fau) 的边权,对整棵树做长链剖分(jiangly:这是典中典长链剖分题)。
把所有的长链的权值排序,然后每次选出前 k k k 大减去就做完啦!

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e6+7,inf=1e18,mod=998244353;
int n,m,k;
vector<bool> bz;
vector<int> val,fa,siz,p;
vector<vector<int>> e;
int gf(int x)
{
	return x==fa[x]?x:fa[x]=gf(fa[x]);
}
int dfs(int u,int fa)
{
	if(bz[u])
	{
		siz[u]=1;
	}
	int mx=0;
	for(auto v:e[u])
	{
		int res=dfs(v,u);
		siz[u]+=siz[v];
		if(mx<res)
			swap(res,mx);
		p.push_back(res);
	}
	if(fa!=0)
		mx+=siz[u]*(val[fa]-val[u]);
	return mx;
}
void O_o()
{
	cin>>n>>m>>k;
	bz.assign(2*n,0);
	for(int i=1; i<=k; i++)
	{
		int x;
		cin>>x;
		bz[x]=1;
	}
	vector<array<int,3>> edge;//l,x,y
	for(int i=1; i<=m; i++)
	{
		int x,y,l;
		cin>>x>>y>>l;
		edge.push_back({l,x,y});
	}
	sort(edge.begin(),edge.end());
	fa.assign(2*n,0);
	for(int i=1; i<=2*n; i++) fa[i]=i;
	int rt=n;
	e.assign(2*n,vector<int>());
	val.assign(2*n,0);
	for(auto [l,x,y]:edge)
	{
		int u=gf(x),v=gf(y);
		if(u==v) continue;
		rt++;
		fa[u]=rt;
		fa[v]=rt;
		val[rt]=l;
		e[rt].push_back(u);
		e[rt].push_back(v);
	}
	siz.assign(2*n,0);
	p.clear();
	p.push_back(dfs(rt,0));
	int ans=k*val[rt];
	sort(p.begin(),p.end(),greater<>());
	for(int i=0; i<n; i++)
	{
		ans-=p[i];
		cout<<ans<<" ";
	}
	cout<<"\n";
}
signed main()
{
	ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
	cout<<fixed<<setprecision(12);
	int T=1;
	cin>>T;
	while(T--)
	{
		O_o();
	}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2194955.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

OBOO鸥柏丨数字化展厅液晶拼接屏联动展馆触摸屏查询一体机信息化

在OBOO鸥柏精心雕琢的多媒体展厅展馆解决方案中&#xff0c;鸥柏液晶拼接屏的多屏联动互动技术犹如一条无形的数字科技纽带&#xff0c;OBOO鸥柏巧妙地将多台商用显示设备编织成一幅幅动态共生的视觉盛宴。鸥柏这项技术&#xff0c;不仅仅是简单的显示设备互联&#xff0c;鸥柏…

73.【C语言】C/C++的内存区域划分

1.内存里的几个区域 除了耳熟能详的栈区,堆区,静态区,还有内核空间,内存映射段,数据段,代码段 2.示意图 3.解释 栈区(stack area):局部变量,函数参数,返回数据,返回地址 内存映射段:将文件映射到内存 映射: 如果看过王爽老师的 《汇编语言 第四版》,其中写到了可以操作B800…

【可答疑】基于51单片机的倒车雷达测距(含仿真、代码、报告、演示视频等)

✨哈喽大家好&#xff0c;这里是每天一杯冰美式oh&#xff0c;985电子本硕&#xff0c;大厂嵌入式在职0.3年&#xff0c;业余时间做做单片机小项目&#xff0c;有需要也可以提供就业指导&#xff08;免费&#xff09;~ &#x1f431;‍&#x1f409;这是51单片机毕业设计100篇…

三、数据链路层(下)

目录 3.6以太网 以太网的分类 Mac地址 以太网数据格式 3.7互联网 数据是如何传输的&#xff1f; 3.8以太网、局域网、互联网的区别 总结&#xff1a; 3.9 vlan基本概念与基本原理 Vlan实现 划分 VLAN 例题 3.10广域网及相关协议 ppp协议 PPP协议所满足的要求 P…

【GitHub】上传文件到GitHub

参考视频&#xff1a;手把手教你在github上传文件_哔哩哔哩_bilibili 1.找到文件夹右键&#xff0c;选择open git bash here 2.完成指令 git initgit add *git commit -m "first commit"3.打开该文件夹&#xff0c;打开隐藏文件.git/config 编辑输入邮箱和GitHub用…

关于Qt音乐播放器进度条拖拽无用的问题解决方案

在使用Qt编写音乐播放器的时候&#xff0c;进度条关联播放音乐基本是必须的。那么在设计的过程中你可能会碰到一个奇怪的问题就是拖拽进度条的时候&#xff0c;可能会报错如下&#xff1a; 然后音乐就卡着不动了。。。 connect(ui->volume_toolButton,&VolumeToolBtn::…

AI大模型,但是在卫星

B站&#xff1a;啥都会一点的研究生公众号&#xff1a;啥都会一点的研究生 AI圈又发生了啥新鲜事&#xff1f; 国星宇航实现全球首次卫星在轨AI大模型技术验证 国星宇航成功完成了全球首次卫星在轨运行AI大模型技术验证&#xff0c;验证了AI大模型在太空中的空间适应性和算力…

解决ERR_PROXY_CONNECTION_FAILED

版权声明 本文原创作者&#xff1a;谷哥的小弟作者博客地址&#xff1a;http://blog.csdn.net/lfdfhl 错误描述 电脑无法正常上网&#xff0c;报错信息如下&#xff1a;ERR_PROXY_CONNECTION_FAILED&#xff1b;图示如下&#xff1a; 解决方案 请按如下步骤和方式解决该问题…

Linux 系统成为隐秘“Perfctl”加密挖矿恶意软件的目标

Aqua Security 的研究人员上周透露&#xff0c;数以千计的 Linux 系统可能感染了极难追踪且持久的“perfctl”&#xff08;或“ perfcc ”&#xff09;加密挖掘恶意软件&#xff0c;许多其他系统仍然面临被入侵的风险。 在观察到的所有攻击中&#xff0c;恶意软件都被用来运行…

C语言入门指南:为大一新生准备

C语言入门指南&#xff1a;为大一新生准备 C语言是许多编程语言的基础&#xff0c;许多现代编程语言&#xff08;如C、Java、Rust等&#xff09;都从C语言中汲取了灵感。因此&#xff0c;学习C语言不仅能帮助你掌握编程的基本概念&#xff0c;还能为学习其他编程语言打下坚实的…

ThinkBook 16+ 锐龙6800h 安装ubuntu键盘失灵

问题&#xff1a;在ThinkBook 16 锐龙6800h 安装ubuntu18.04 出现笔记本键盘按下延迟非常高&#xff0c;输出卡死的情况&#xff0c;但是外接键盘可以正常使用 解决&#xff1a;更新内核 1、进入 https://kernel.ubuntu.com/~kernel-ppa/mainline/ 下载所需内核版本&#x…

Array类、引用类型

前面我们对数组的增加,删除,查找,更改都需要进行循环遍历,非常的麻烦。C#系统为我们提供了Array类,在这个类中定义了许多对数组进行操作的方法,我们可以直接用,从而提高效率。 索引查找: int[] a = { 1, 2, 3, 4, 3 }; int b=Array.IndexOf(a, 3);//第一个参数为数组…

判断是否为二叉排序树(二叉搜索树,二叉查找树)

1.判断给定的二叉树是否为二叉排序树&#xff0c;如果是返回1&#xff0c;不是返回0。 思想&#xff1a; 二叉树是左子树<根<右子树。中序遍历是递增有序&#xff0c;可以通过比较当前结点与前驱关系来进行判断。 代码&#xff1a; //pre为全局变量&#xff0c;保存当…

xmltodict 处理 XML 数据案例解析

简介&#xff1a;xmltodict 是一个用于将 XML 数据转换为 Python 字典的轻量级模块。它简化了 XML 数据的解析和处理&#xff0c;使得在 Python 中操作 XML 变得更加直观和方便。这个模块适合用于数据交换、配置文件解析等需要 XML 数据处理的场景。 历史攻略&#xff1a; loc…

软件验证与确认实验三-数据驱动测试

目录 1. 实验目的及要求.................................................................................................... 3 2. 实验软硬件环境.................................................................................................... 3 …

ASP.NetCore---I18n(internationalization)多语言版本的应用

文章目录 0.实现的效果如下1.创建新项目I18nBaseDemo2.添加页面中的下拉框3.在HomeController中添加ChangeLanguage方法4.在Progress.cs 文件中添加如下代码&#xff1a;5. 在progress.cs中添加code6.添加Resource资源文件7.在页面中引用i18n的变量8. 重启项目&#xff0c;应该…

【多线程】详解 CAS 机制

&#x1f970;&#x1f970;&#x1f970;来都来了&#xff0c;不妨点个关注叭&#xff01; &#x1f449;博客主页&#xff1a;欢迎各位大佬!&#x1f448; 文章目录 1. CAS 是什么1.1 CAS 具体步骤1.2 CAS 伪代码 2. CAS 的应用2.1 实现原子类2.1.1 AtomInteger 类2.1.2 伪代…

【2024最新】基于springboot+vue的教师人事档案管理系统lw+ppt

作者&#xff1a;计算机搬砖家 开发技术&#xff1a;SpringBoot、php、Python、小程序、SSM、Vue、MySQL、JSP、ElementUI等&#xff0c;“文末源码”。 专栏推荐&#xff1a;SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码 精品专栏&#xff1a;Java精选实战项…

wxPython中wx.ListCtrl用法(样式和事件)

wx.ListCtrl是一个列表组件&#xff0c;可以以列表视图&#xff08;list view&#xff09;、报表视图&#xff08;report view&#xff09;、图标视图&#xff08;icon view&#xff09;和小图标视图&#xff08;small icon view&#xff09;等多种模式显示列表。 组件样式 wx…

c++grpc详解

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 一.简介支持的语言使用场景特点 二.传输原理protobuf传输HTTP2.0流和帧 三.grpc的四种模式1.一元RPC模式2.服务端流3.客户端流4.双向流 四.基本流程 一.简介 gRPC …