NOIP2018-S-DAY1-3-赛道修建(洛谷P5021)的题解

目录

题目

原题描述:

题目描述

输入格式

输出格式

输入输出样例

主要思路:

check:

真正的code:


原题描述:
 

题目描述

C 城将要举办一系列的赛车比赛。在比赛前,需要在城内修建 m 条赛道。

C 城一共有 n 个路口,这些路口编号为1,2,...,n,有 n-1条适合于修建赛道的双向通行的道路,每条道路连接着两个路口。其中,第i条道路连接的两个路口编号为a_i和 b_i,该道路的长度为 l_i。借助这 n-1 条道路,从任何一个路口出发都能到达其他所有的路口。

一条赛道是一组互不相同的道路 e_1,e_2,..,e_k,满足可以从某个路口出发,依次经过 道路 e_1,e_2,..,e_k(每条道路经过一次,不允许调头)到达另一个路口。一条赛道的长度等于经过的各道路的长度之和。为保证安全,要求每条道路至多被一条赛道经过。

目前赛道修建的方案尚未确定。你的任务是设计一种赛道修建的方案,使得修建的 m 条赛道中长度最小的赛道长度最大(即m 条赛道中最短赛道的长度尽可能大)

输入格式

输入文件第一行包含两个由空格分隔的正整数 n,m,分别表示路口数及需要修建的 赛道数。

接下来 n-1 行,第i行包含三个正整数 a_ib_i,l_i,表示第i条适合于修建赛道的道 路连接的两个路口编号及道路长度。保证任意两个路口均可通过这 n-1 条道路相互到达。每行中相邻两数之间均由一个空格分隔。

输出格式

输出共一行,包含一个整数,表示长度最小的赛道长度的最大值。

输入输出样例

输入 #1

7 1 
1 2 10 
1 3 5 
2 4 9 
2 5 8 
3 6 6 
3 7 7

输出 #1

31

输入 #2

9 3 
1 2 6 
2 3 3 
3 4 5 
4 5 10 
6 2 4 
7 2 9 
8 4 7 
9 4 4

输出 #2

15

 

主要思路:

题目说的很复杂,实际上很简单,就是给你一棵树,然后让你找到m条链,每条链没有公共边,然后问长度最小的链长度最大是多少。

首先,看道这题,先想到二分。

我们可以二分答案,就是最小的链的长度。

接着就是check:

check:

我们可以用个dfs,tmp[x] 就是到x的最大边,则枚举所有到x的边,然后dfs()一下,接着tmp[x] = tmp[it]+边权。

dfs部分代码:

void dfs(int x,int fa,int k)//x是当前节点,k是要达成的长度
{
//	cout<<x<<' '<<fa<<' '<<k<<'\n';
	tmp[x] = 0;
	multiset<int> s;
	for(auto it:v[x])
	{
		if(it.first!=fa)
		{
			dfs(it.first,x,k);
			tmp[x] = tmp[it.first]+it.second;//tmp加上
			if(tmp[x]>=k)
			{
				ans++;//ans是可成立的边数
			}
			else//否则,就要放进multiset
			{
				s.insert(tmp[x]);
			}
		}
	}
}

这里的multiset就是存储子树内还不够的长度。

接着,我们看一下s里的元素,s非空时,而且s只有一个元素,就说明这个数和谁都不能匹配,那么就要和他的爷爷们连边了(只有一个点可以和爷爷连边)

为了给爷爷们减轻负担,所以我们希望让那个点的tmp尽量大(这就是一种贪心)。

否则,就lower_bound(k-s.begin());

我们从小的选大的,为啥呢?

从之前的结论得到,我们要尽量给爷爷们减少麻烦,所以要选大的,所以是小选大

所以最后dfs和check代码长这样

vector<vector<pair<int,int>>>v(500010);
int ans=0;
int tmp[500010];
void dfs(int x,int fa,int k)
{
//	cout<<x<<' '<<fa<<' '<<k<<'\n';
	tmp[x] = 0;
	multiset<int> s;
	for(auto it:v[x])
	{
		if(it.first!=fa)
		{
			dfs(it.first,x,k);
			tmp[x] = tmp[it.first]+it.second;
			if(tmp[x]>=k)
			{
				ans++;
			}
			else
			{
				s.insert(tmp[x]);
			}
		}
	}
	int mx=0;
	while(!s.empty())//贪心思想
	{
		if(s.size() == 1)
		{
			tmp[x] = max(mx,*s.begin());
			return ;
		}
		auto it=s.lower_bound(k-*s.begin());
		if(it == s.begin()&&s.count(*it) == 1)
		{
			it++;
		}
		if(it == s.end())
		{
			mx = max(mx,*s.begin());
			s.erase(s.find(*s.begin()));
		}
		else
		{
			ans++;
			s.erase(s.find(*s.begin()));
			s.erase(s.find(*it));
		}
	}
	tmp[x] = mx;
}
bool check(int mid)
{
	ans = 0;
	dfs(1,-1,mid);
	return ans>=m;
}

接着就差不多搞定了。

但还有一个小细节。

就是二分的r他的上限不是自己定义的,而是树的直径。

否则会被这个hack:

2 0
1 2 1000

输出:

1000

真正的code:
 

#include<bits/stdc++.h>
using namespace std;
int n,m;
vector<vector<pair<int,int>>>v(500010);
int ans=0;
int tmp[500010];
void dfs(int x,int fa,int k)
{
//	cout<<x<<' '<<fa<<' '<<k<<'\n';
	tmp[x] = 0;
	multiset<int> s;
	for(auto it:v[x])
	{
		if(it.first!=fa)
		{
			dfs(it.first,x,k);
			tmp[x] = tmp[it.first]+it.second;
			if(tmp[x]>=k)
			{
				ans++;
			}
			else
			{
				s.insert(tmp[x]);
			}
		}
	}
	int mx=0;
	while(!s.empty())
	{
		if(s.size() == 1)
		{
			tmp[x] = max(mx,*s.begin());
			return ;
		}
		auto it=s.lower_bound(k-*s.begin());
		if(it == s.begin()&&s.count(*it) == 1)
		{
			it++;
		}
		if(it == s.end())
		{
			mx = max(mx,*s.begin());
			s.erase(s.find(*s.begin()));
		}
		else
		{
			ans++;
			s.erase(s.find(*s.begin()));
			s.erase(s.find(*it));
		}
	}
	tmp[x] = mx;
}
bool check(int mid)
{
	ans = 0;
	dfs(1,-1,mid);
	return ans>=m;
}
int up;
int dfs1(int x,int fa)//数的直径
{
	int sum1=0,sum2=0;
	for(auto it:v[x])
	{
		if(it.first == fa)
		{
			continue;
		}
		sum2=max(sum2,dfs1(it.first,x)+it.second);
		if(sum1<sum2)
		{
			swap(sum1,sum2);
		}
	}
	up=max(up,sum1+sum2);
	return sum1;
}
int main()
{
//	freopen("sample (13).in","r",stdin);
	ios::sync_with_stdio(0);
	cin.tie(0);
	cin>>n>>m;
	for(int i=1;i<n;i++)
	{
		int x,y,z;
		cin>>x>>y>>z;
		v[x].push_back({y,z});
		v[y].push_back({x,z});
	}
	dfs1(1,0);
	int l=0,r=up;
	int ans=0;
	while(l<=r)
	{
		int mid=(l+r)/2;
		if(check(mid))
		{
			ans = mid;
			l = mid+1;
		}
		else
		{
			r = mid-1;
		}
	}
	cout<<ans;
	return 0;
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

gitee分支管理,合并冲突

1、gitee展示分支 git branch 2、展示远程分支 git branch -r 3、新建分支 git branch base 4、切换分支 git checkout base 合并冲突 当代码在服务器上被提交了&#xff0c;再在本地提交会提示报错 点击merge

从GPT入门,到R语言基础与作图、回归模型分析、混合效应模型、多元统计分析及结构方程模型、Meta分析、随机森林模型及贝叶斯回归分析综合应用等专题及实战案例

目录 专题一 GPT及大语言模型简介及使用入门 专题二 GPT与R语言基础与作图&#xff08;ggplot2&#xff09; 专题三 GPT与R语言回归模型&#xff08;lm&glm&#xff09; 专题四 GPT与混合效应模型&#xff08;lmm&glmm&#xff09; 专题五 GPT与多元统计分析&…

中国社会科学院与美国杜兰大学金融管理硕士——二月二,抬头皆是惊喜

在繁忙的都市生活中&#xff0c;每个人都在为自己的未来打拼&#xff0c;寻找着属于自己的那片天空。二月二&#xff0c;龙抬头&#xff0c;象征着春天的到来&#xff0c;万物复苏。在这个特殊的日子里&#xff0c;对于那些追求学术与职业双重成就的人来说&#xff0c;&#xf…

【Java常用API】正则表达式的基础使用

&#x1f36c; 博主介绍&#x1f468;‍&#x1f393; 博主介绍&#xff1a;大家好&#xff0c;我是 hacker-routing &#xff0c;很高兴认识大家~ ✨主攻领域&#xff1a;【渗透领域】【应急响应】 【Java、PHP】 【VulnHub靶场复现】【面试分析】 &#x1f389;点赞➕评论➕收…

zabbix5监控tomcat

zabbix tomcat客户端配置 1、配置tomcat catalina.sh文件 CATALINA_OPTS"$CATALINA_OPTS -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port12345 -Dcom.sun.management.jmxremote.authenticatefalse -Dcom.sun.management.jmxremote.sslfalse -Djav…

1.Python是什么?——跟老吕学Python编程

1.Python是什么&#xff1f;——跟老吕学Python编程 Python是一种什么样的语言&#xff1f;Python的优点Python的缺点 Python发展历史Python的起源Python版本发展史 Python的价值学Python可以做什么职业&#xff1f;Python可以做什么应用&#xff1f; Python是一种什么样的语言…

WPF —— TextBlock、LineBreak RadioButton控件详解

一:TextBlock 1&#xff1a;TextBlock 简介 <LineBreak/> 换行 显示文本 标签内容和content属性共存 2、TextBlock 常用的属性 Foreground&#xff1a;TextBlock的文本内容的颜色。 Background&#xff1a;背景&#xff0c;获取或设置要用于填充内容区域背景的 Brush…

VMware 集群-虚拟机配置反亲和性(互斥)

简介 博客&#xff1a;https://songxwn.com/ 为实现应用系统的冗余&#xff0c;经常会双机或者多机部署&#xff08;如数据库集群等&#xff09;。在VMware 集群里面&#xff0c;要保证不同应用集群的节点虚拟机在不同的物理宿主机上&#xff0c;防止单个宿主机故障&#xff…

EasyNVR级联EasyCVR后,EasyCVR播放视频导致EasyNVR崩溃是什么原因?

视频综合管理平台EasyCVR视频监控系统支持多协议接入、兼容多类型设备&#xff0c;平台可以将监控区域内所有部署的监控设备进行统一接入与集中汇聚管理&#xff0c;实现对监控区域的实时视频监控、录像与存储、设备管理、云台控制、语音对讲、级联共享等&#xff0c;在监控中心…

指纹挂锁方案——采用ACH512或ACM32FP4指纹芯片和88*112传感器,指纹识别速度快,BOM成本低

方案概述 指纹挂锁方案采用ACH512或ACM32FP4指纹芯片和88*112传感器&#xff0c;指纹识别速度快&#xff0c;BOM成本低&#xff0c;非常适合挂锁、内门锁、箱包锁、箱柜锁等场景。 方案特点 • 主控算法单芯片&#xff1a;ACH512或ACM32FP4 • 传感器分辨率&#xff1a;88*11…

探究精酿啤酒的秘密:原料中的天然酵母与纯净水质

在啤酒的世界中&#xff0c;Fendi Club精酿啤酒以其与众不同的口感和深远的余味吸引了全球的啤酒爱好者。而这一切&#xff0c;都归功于其选用的上好原料&#xff0c;特别是天然酵母和纯净水质。 天然酵母是啤酒的灵魂。与工业生产的啤酒酵母不同&#xff0c;天然酵母富含丰富的…

跨境账号养号怎么做?Facebook、亚马逊运营必看

之前我们讨论过很多关于代理器的问题。它们的工作原理是什么?在不同的软件中要使用那些代理服务器?这些代理服务器之间的区别是什么?什么是反检测浏览器等等。 除了这些问题&#xff0c;相信很多人也会关心在使用不同平台的时代理器的选择问题。比如&#xff0c;为什么最好…

使用helm部署clickhouse

&#xff08;作者&#xff1a;陈玓玏&#xff09; 前置条件 已安装 Kubernetes 集群&#xff1b; 已安装 Helm 包管理工具。 部署 1 添加 RadonDB ClickHouse 的 Helm 仓库 helm repo add ck https://radondb.github.io/radondb-clickhouse-kubernetes/ helm repo upd…

精品基于Springboot的聊天交友系统的设计与实现

《[含文档PPT源码等]精品基于Springboot的聊天交友系统的设计与实现[包运行成功]》该项目含有源码、文档、PPT、配套开发软件、软件安装教程、项目发布教程、包运行成功&#xff01; 软件开发环境及开发工具&#xff1a; Java——涉及技术&#xff1a; 前端使用技术&#xf…

js实现导出/下载excel文件

js实现导出/下载excel文件 // response 为导出接口返回数据&#xff0c;如上图 const exportExcel (response, fileName:string) >{const blob new Blob([response.data], {type: response.headers[content-type] //使用获取的excel格式});const downloadElement documen…

Java 三大并大特性-有序性介绍(结合代码、分析源码)

目录 一、概念解析 二、 有序性代码例子 2.1 代码 2.2 执行结果 三、 指令重排序机制 3.1 为什么要引入指令重排序 3.2 指令重排序的分类 3.2.1 编译器优化重排序 3.2.2 指令级并行的重排序 3.2.3 内存系统的重排 3.3 指令重排序规范 3.3.1 as-if-serial 规范 3.3…

基于boost库的搜索引擎项目

文章目录 一、项目背景二、什么样的搜索引擎三、搜索引擎的宏观图原理四、Parse模块4.1下载boost库源代码4.2提取boost库中以.html为结尾的文件4.2.1 boost库的简单使用 4.3数据清洗(去标签化)4.3.1数据清洗的具体实现 4.4将清洗后的数据写入到raw.txt文件中 五、正排索引 vs 倒…

最新android icon和splashScreen适配兼容至2024android

android在12做了splashScreen的变动&#xff0c;即&#xff0c;android12有自带的screenSplash过渡&#xff0c;不论你是否自己有变化&#xff0c;都会插入该动画。 android8做了icon的巨大变动。13做了图标的主题兼容。 一、icon制作 制作 使用android自带的工具&#xff0…

甜甜圈和贪吃蛇的后续

代码复现-项目复现 代码复现 云课五分钟-02第一个代码复现-终端甜甜圈C-CSDN博客 项目复现 云课五分钟-03第一个开源游戏复现-贪吃蛇-CSDN博客 不同的地图 加入班级和标识 循序渐进 这些案例都是来源网络&#xff0c;只是方便熟悉一下云课使用过程。 此部分学生掌握情况非…

阿里云数据湖存储加速套件JindoData

计算存储分离已经成为云计算的一种发展趋势。在计算存储分离之前&#xff0c;普遍采用的是传统的计算存储相互融合的架构&#xff0c;但是这种架构存在一定的问题&#xff0c;比如在集群扩容的时候会面临计算能力和存储能力相互不匹配的问题。用户在某些情况下只需要扩容计算能…
最新文章