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

news2024/12/25 1:20:42

目录

题目

原题描述:

题目描述

输入格式

输出格式

输入输出样例

主要思路:

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.coloradmin.cn/o/1510844.html

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

相关文章

天梯赛的赛场安排(Python)

作者 陈越 单位 浙江大学 天梯赛使用 OMS 监考系统&#xff0c;需要将参赛队员安排到系统中的虚拟赛场里&#xff0c;并为每个赛场分配一位监考老师。每位监考老师需要联系自己赛场内队员对应的教练们&#xff0c;以便发放比赛账号。为了尽可能减少教练和监考的沟通负担&#…

打造私人云笔记,创造舒适的写作空间

搭建Minio 图片文件服务器 &#xff08;树莓派4B搭建Minio公网云服务器用nps内网穿透&#xff09;Typora 安装客户端 --> 可以利用免费gitee管理文档利用Typora 图像自定义文件上传功能 Minio强大的API功能 一、树莓派4B 64bit raspberry 操作系统 Docker Minio 图片文件…

CentOS本地部署Tale博客并结合内网穿透实现公网访问本地网站

文章目录 前言1. Tale网站搭建1.1 检查本地环境1.2 部署Tale个人博客系统1.3 启动Tale服务1.4 访问博客地址 2. Linux安装Cpolar内网穿透3. 创建Tale博客公网地址4. 使用公网地址访问Tale 前言 今天给大家带来一款基于 Java 语言的轻量级博客开源项目——Tale&#xff0c;Tale…

Python 配置信息的添加和获取

1.效果如下&#xff1a; 2.代码如下&#xff1a; from configparser import ConfigParser import threadingclass Config():_instance_lock threading.Lock()classmethoddef instance(cls, *args, **kwargs):if not hasattr(Config, "_instance"):with Config._ins…

ELK 基本操作

文章目录 1.Elasticsearch-head2.Kibana2.1.功能简介2.2.Management2.3.Discover2.4.Dev Tools 开源中间件 # Elastic Stackhttps://iothub.org.cn/docs/middleware/ https://iothub.org.cn/docs/middleware/elk/elk-use/1.Elasticsearch-head 2.Kibana 2.1.功能简介 2.2.Man…

电脑桌面便签下载,电脑桌面便签软件哪个好

电脑桌面便签下载&#xff0c;电脑桌面便签软件哪个好&#xff1f;在日常工作生活中&#xff0c;我们经常会遇到许多琐碎的事情需要记录和安排&#xff0c;这时候电脑桌面便签就成为了一个不可或缺的工具。而如今&#xff0c;在电脑时代的今天&#xff0c;电脑桌面便签软件更是…

扭蛋机小程序,扭蛋与互联网结合下的商机

扭蛋机作为一种娱乐消费模式&#xff0c;受众群体不再局限于儿童&#xff0c;也吸引了众多的年轻消费者。扭蛋机具有较大的随机性&#xff0c;玩具商品随机掉落&#xff0c;在购买前消费者完全不知道扭蛋中的商品是什么&#xff0c;这种未知性带来的惊喜感是吸引众多消费者的主…

MyBatis框架2

目录 一、Sql编写高级特性-批量增删 1.SQL-foreach-批量删除 1.1.批量删除方法 1.2编写SQL 1.3.编写测试 2.动态SQL-foreach-批量插入 2.1.映射器批量插入方法 2.2.编写SQL 2.3.编写测试 二、Sql编写高级特性-多对一 1.多对一保存 1.1.创建员工部门Domain 1.2.创建员…

远程同声传译如何实现?哪里提供专业的远程同声传译?

远程同传声传译&#xff0c;即线上同传翻译&#xff0c;是指翻译员通过非现场的网络方式进行的同声传译(实时翻译)。远程同声传译的实现依赖于一系列先进的技术手段和高效的协作流程。这一服务模式的出现&#xff0c;不仅打破了传统同声传译的地域限制&#xff0c;还为全球范围…

【JavaEE Spring 项目】消息队列的设计

消息队列的设计 一、消息队列的背景知识二、需求分析核心概念⼀个⽣产者, ⼀个消费者N 个⽣产者, N 个消费者Broker Server 中的相关概念核⼼ API交换机类型 (Exchange Type)持久化⽹络通信消息应答 三、 模块划分四、 项⽬创建五、创建核心类创建 Exchange创建 MSGQUeue创建 B…

9个免费游戏后端平台

在这篇文章中&#xff0c;您将看到 九个免费的游戏服务平台提供商&#xff0c;这可以帮助您开始在线多人游戏&#xff0c;而无需预先投入大量资金。 每个提供商都有非常独特的功能&#xff0c;因此成本应该只是决定时要考虑的方面之一。 我还从低预算项目的角度对免费提供商进…

基于单片机的篮球计分器设计

在当今的体育赛事中,比赛的计分系统对观众和运动员尤为重要,观众可以根据比分的实时显示为自己支持的队伍呐喊助威,运动员更是要靠着计分器来把握比赛的节奏,包括攻防转换、替补换人以及赛间休息等等。因此,为了让比赛进行得更加专业化和流畅化,我们有必要对比赛的计分系…

基于深度学习的鱼类分类检测系统(含UI界面、yolov8、Python代码、数据集)

项目介绍 项目中所用到的算法模型和数据集等信息如下&#xff1a; 算法模型&#xff1a;     yolov8 yolov8主要包含以下几种创新&#xff1a;         1. 可以任意更换主干结构&#xff0c;支持几百种网络主干。 数据集&#xff1a;     网上下载的数据集&#x…

MongoDB性能最佳实践:硬件和操作系统配置

欢迎阅读有关MongoDB性能最佳实践的系列博文。在往期文章中&#xff0c;我们已经讨论过查询模式和性能分析、事务和读/写关注等实现大规模性能的关键考虑因素。在本篇文章中&#xff0c;我们将讨论硬件和操作系统配置。 如果您在阿里云上部署MongoDB&#xff0c;那么阿里云会为…

网站做好这些准备后,上线SEO效果最佳

做网站很多年&#xff0c;也就最近两年理解这个精髓吗。网站上线之前&#xff0c;先在本地做好调试&#xff0c;修改&#xff0c;内容填充。这样后续做SEO会有意想不到的惊喜。 以前我自己做网站&#xff0c;都是直接解析域名到程序安装&#xff0c;上线就是一个空网站&#xf…

【项目】仿muduo库One Thread One Loop式主从Reactor模型实现高并发服务器

本篇博客记录从0到1实现一个仿mudo库的One Thread One Loop式主从Reactor模型的高并发服务器组件。 在此之前我们要明确的是&#xff0c;该项目仅作为一个高并发服务器组件&#xff0c;因此该项目并不包含实际的业务需求处理内容。 前置知识背景 一、HTTP服务器 概念&#xf…

双指针算法练习

27. 移除元素 题目 给你一个数组 nums 和一个值 val&#xff0c;你需要 原地 移除所有数值等于 val 的元素&#xff0c;并返回移除后数组的新长度。 不要使用额外的数组空间&#xff0c;你必须仅使用 O(1) 额外空间并 原地 修改输入数组。 元素的顺序可以改变。你不需要考虑…

conda安装playwright

进入conda安装目录激活环境 D:\Anacoda3>conda activate base 安装playwright &#xff08;base&#xff09;D:\Anacoda3>pip3 install playwright -i https://pypi.tuna.tsinghua.edu.cn/simple &#xff08;base&#xff09;D:\Anacoda3>python -m playwright insta…

学习Java的第八天

本节我们重点研究对象和类的概念。 对象&#xff08;Object&#xff09;是一个应用系统中的用来描述客观事物的实体&#xff0c;是有特定属性和行为&#xff08;方法&#xff09;的基本运行单位。是类的一个特殊状态下的实例。对象可以是一个实体、一个名词、一个可以想象为有…

【C++】AVL树的插入、旋转

目录 一、AVL树介绍1.1 概念1.2 定义 二、AVL树的实现2.1 插入2.2 旋转2.2.1 左单旋2.2.2 右单旋2.2.3 左右双旋2.2.4 右左双旋 一、AVL树介绍 1.1 概念 AVL树是高度平衡的二叉搜索树&#xff0c;相比普通的二叉搜索树&#xff0c;它防止了变成单支树的情况。因为AVL树每插入…