Noip2018Day1T3 赛道修建
problem
给出一棵有边权的树。一条链的权值定义为该链所经过的边的边权值和。需要选出\(m\)条链,求\(m\)条链中权值最小的链的权值最大是多少。
solution
首先显然二分。
然后考虑如何判断二分出来的一个答案\(x\)是否是可行的。也就是能否选出\(m\)条链,每条链权值都大于等于\(x\)。这个其实是贪心。
定义直链为从一个某个点的祖先到该点的路径。
可以发现每条链要么就是一条直链,要么由两条直链在某个点处合并起来得到。
贪心的地方在于,对于每个点肯定都是优先将能合成的直链合成。然后再保证向上传递的直链长度最大。因为即便向上传递的长度特别大,产生的贡献也做多只能是\(1\)。所以要先保证在当前子树上合成最多的链。
然后问题就变成了在一棵子树内得到一些直链长度。现在把这些直链两两合并成权值大于等于\(x\)的链。然后保证剩下的直链长度最大。
这里可以二分答案一下。也可以用个\(multiset\)处理。反正是很可做的一个问题。
代码中有各档部分分,BF5为正解
code
#include<set>
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<ctime>
#include<algorithm>
#include<queue>
#include<cstring>
using namespace std;
typedef long long ll;
const int N = 100010;
ll read() {
ll x = 0,f = 1;char c = getchar();
while(c < '0' || c > '9') {
if(c == '-') f = -1;
c = getchar();
}
while(c >= '0' && c <= '9') {
x = x * 10 + c - '0';
c = getchar();
}
return x * f;
}
int n,m;
struct node {
int v,nxt,w;
}e[N << 1];
int head[N],ejs;
void add(int u,int v,int w) {
e[++ejs].v = v;e[ejs].nxt = head[u];head[u] = ejs;e[ejs].w = w;
}
namespace BF1 {
int dis[N];
void dfs(int u,int fa) {
for(int i = head[u];i;i = e[i].nxt) {
int v = e[i].v;
if(v == fa) continue;
dis[v] = dis[u] + e[i].w;
dfs(v,u);
}
}
void main() {
dfs(1,0);
int x = 0;
for(int i = 1;i <= n;++i) if(dis[i] > dis[x]) x = i;
// cout<<x<<endl;
memset(dis,0,sizeof(dis));
dfs(x,0);
int ans = 0;
for(int i = 1;i <= n;++i) ans = max(ans,dis[i]);
cout<<ans;
}
}
namespace BF2 {
int a[N],cnt;
int check(int x) {
int p = 1,ret = 0;
for(int i = cnt;i > p;--i) {
if(a[i] > x && i > p) {ret++;continue;}
while(a[p] + a[i] < x && p < i) ++p;
if(p < i) ret++,p++;
else break;
}
return ret;
}
void main() {
int l = 100000,r = 0;
for(int i = 1;i <= ejs;i += 2) a[++cnt] = e[i].w,l = min(l,a[cnt]),r += a[cnt];
sort(a + 1,a + cnt + 1);
int ans = 0;
while(l <= r) {
int mid = (l + r) >> 1;
if(check(mid) >= m) ans = mid,l = mid + 1;
else r = mid - 1;
}
cout<<ans<<endl;
}
}
int du[N];
namespace BF3 {
int a[N],cnt;
void dfs(int u,int fa) {
for(int i = head[u];i;i = e[i].nxt) {
int v = e[i].v;
if(v == fa) continue;
a[++cnt] = e[i].w;
dfs(v,u);
}
}
int check(int x) {
int now = 0,ret = 0;
for(int i = 1;i <= cnt;++i) {
now += a[i];
if(now >= x) now = 0,ret ++;
}
return ret;
}
void main() {
for(int i = 1;i <= n;++i)
if(du[i] == 1) {dfs(i,0);break;}
int l = 1000000,r = 0;
for(int i = 1;i <= ejs;i += 2) {
l = min(l,e[i].w);r += e[i].w;
}
int ans = 0;
while(l <= r) {
int mid = (l + r) >> 1;
if(check(mid) >= m) ans = mid,l = mid + 1;
else r = mid - 1;
}
cout<<ans<<endl;
}
}
int L = 100000,R;
namespace BF5 {
int ANS;
int dfs(int u,int fa,int x) {
multiset<int>s;
int ret = 0;
// if(!s.empty()) printf("%d\n",u);
for(int i = head[u];i;i = e[i].nxt) {
int v = e[i].v;
if(v == fa) continue;
int k = dfs(v,u,x);
if(k + e[i].w >= x) ANS++;
else s.insert(k + e[i].w);
}
while(!s.empty()) {
multiset<int>::iterator it = s.begin();
int k = *it;
s.erase(it);
multiset<int>::iterator is = s.lower_bound(x - k);
if(is == s.end()) ret = max(ret,k);
else ANS++,s.erase(is);
}
// s.clear();
// printf("%d %d\n",u,ret);
return ret;
}
void main() {
int l = L,r = R,ans = 0;
while(l <= r) {
int mid =(l + r) >> 1;
ANS = 0;dfs(1,0,mid);
if(ANS >= m) ans = mid,l = mid + 1;
else r = mid - 1;
}
cout<<ans;
}
}
int main() {
n = read(),m = read();
int bz1 = 1,bz2 = 1;
for(int i = 1;i < n;++i) {
int u = read(),v = read(),w = read();
L = min(L,w);R += w;
du[u]++;du[v]++;
add(u,v,w);add(v,u,w);
if(u != 1) bz1 = 0;
if(v != u + 1) bz2 = 0;
}
if(m == 1) {BF1::main();return 0;}
if(bz1) {BF2::main();return 0;}
if(bz2) {BF3::main();return 0;}
BF5::main();
return 0;
}
/*
7 1
1 2 10
1 3 5
2 4 9
2 5 8
3 6 6
3 7 7
*/
Noip2018Day1T3 赛道修建的更多相关文章
- Luogu5021 [NOIP2018]赛道修建
Luogu5021 [NOIP2018]赛道修建 一棵大小为 \(n\) 的树,边带权.选 \(m\) 条链使得长度和最小的链最大. \(m<n\leq5\times10^4\) 贪心,二分答案 ...
- [NOIp2018提高组]赛道修建
[NOIp2018提高组]赛道修建 题目大意: 给你一棵\(n(n\le5\times10^4)\)个结点的树,从中找出\(m\)个没有公共边的路径,使得第\(m\)长的路径最长.问第\(m\)长的路 ...
- noip2018 D1T3 赛道修建
题目描述 C 城将要举办一系列的赛车比赛.在比赛前,需要在城内修建 mm 条赛道. C 城一共有 nn 个路口,这些路口编号为 1,2,…,n1,2,…,n,有 n-1n−1 条适合于修建赛道的双向通 ...
- noip 2018 D1T3 赛道修建
noip 2018 D1T3 赛道修建 首先考虑二分答案,这时需要的就是对于一个长度求出能在树中选出来的最多的路径条数.考虑到一条路径是由一条向上的路径与一条向下的路径构成,或者仅仅是向上或向下的路径 ...
- 【LG5021】[NOIP2018]赛道修建
[LG5021][NOIP2018]赛道修建 题面 洛谷 题解 NOIP之前做过增强版还没做出来\(QAQ\) 一看到题目中的最大值最小,就很容易想到二分答案 重点是考虑如何\(check\) 设\( ...
- 【noip2018】【luogu5021】赛道修建
题目描述 C 城将要举办一系列的赛车比赛.在比赛前,需要在城内修建 mm 条赛道. C 城一共有 nn 个路口,这些路口编号为 1,2,…,n1,2,…,n,有 n-1n−1 条适合于修建赛道的双向通 ...
- 竞赛题解 - NOIP2018 赛道修建
\(\mathcal {NOIP2018}\) 赛道修建 - 竞赛题解 额--考试的时候大概猜到正解,但是时间不够了,不敢写,就写了骗分QwQ 现在把坑填好了~ 题目 (Copy from 洛谷) 题 ...
- [NOIP2018TG]赛道修建
[NOIP2018TG]赛道修建 考场上multiset调不出啊啊啊!!! 首先肯定是二分答案 做树形dp,f[i]表示i点的子树两两匹配后剩下的最长长度 匹配可以用multiset维护 但是菊花图跑 ...
- 【题解】 P5021赛道修建
[题解]P5021 赛道修建 二分加贪心,轻松拿省一(我没有QAQ) 题干有提示: 输出格式: 输出共一行,包含一个整数,表示长度最小的赛道长度的最大值. 注意到没,最小的最大值,还要多明显? 那么我 ...
随机推荐
- 给spark submit main传递参数
https://www.jianshu.com/p/1d41174441b6 注意传递过去的默认是string,如果修改只能在代码中修改
- Abp RabbitMqEventBus
RabbitMQ安装介绍查看该网址 两个App都要配置 appsettings.json { "RabbitMQ": { "Connections": { &q ...
- unittest框架之 BeautifulReport 模板报告生成的正确姿势
使用unittest框架的自动化测试,报告一定很重要,目前介绍一个比较高大上的报告模板 BeautifulReport.如果首次使用的话需要安装 pip install beautifulreport ...
- jmeter相关知识学习记录
基于Jmeter5.2.1 断言之响应断言 响应断言:对服务器的响应接口进行断言校验,来判断接口测试得到的接口返回值是否正确. 测试字段就是指要断言的内容的匹配处. 响应文本:就是响应的body部分: ...
- 一些你不知道的js特性【一】
关于js 我们知道完整的js包括三个方面ECMAScript.DOM(文档对象模型).BOM(浏览器对象模型). ECMAScript定义了与宿主无关的预言基础,比如:语法(包含正则语法).类型.语句 ...
- Java 添加Word页眉、页脚
本篇文章将介绍通过java程序来添加Word页眉页脚的方法.鉴于在不同文档中,对页眉页脚的操作要求不同,文章将分别从以下几种情况来阐述: 1.添加页眉页脚 添加图片到页眉 添加文本到页眉 添加页码 2 ...
- Asp .Net Core Excel导入和导出
ASP .Net Core使用EPPlus实现Api导入导出,这里使用是EPPlus 4.5.2.1版本,.Net Core 2.2.在linux上运行的时候需要安装libgdiplus . 下面我们 ...
- C#函数的递归
using System; namespace ConsoleApp3 { class Program { static void Main(string[] args) { ); Console.W ...
- (转)GitHub Desktop 拉取 GitHub上 Tag 版本代码
转自:GitHub Desktop 拉取 GitHub上 Tag 版本代码 一直在使用 GitHub Desktop 图形化 git 管理工具,统一项目框架版本时需要切换到ThinkPHP Tag 分 ...
- 一篇文章,彻底理解ReentrantLock
本人免费整理了Java高级资料,涵盖了Java.Redis.MongoDB.MySQL.Zookeeper.Spring Cloud.Dubbo高并发分布式等教程,一共30G,需要自己领取.传送门:h ...