初见安~本狸参加了2018年的NOIP,然后到现在【看题解】才能过Day1 T3……tcl……QwQ

本篇题解及代码有参考洛谷题解。

本篇夹带了对于二分深切的痛恨。请自行忽略。

传送门:洛谷 P5021

题目描述

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

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

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

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

输入格式:

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

接下来 n-1n−1 行,第 ii 行包含三个正整数 a_i,b_i,l_iai​,bi​,li​,表示第 ii 条适合于修建赛道的道 路连接的两个路口编号及道路长度。保证任意两个路口均可通过这 n-1n−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

说明

【输入输出样例 1 说明】

所有路口及适合于修建赛道的道路如下图所示:

道路旁括号内的数字表示道路的编号,非括号内的数字表示道路长度。 需要修建 11 条赛道。可以修建经过第 3,1,2,63,1,2,6 条道路的赛道(从路口 44 到路口 77), 则该赛道的长度为 9 + 10 + 5 + 7 = 319+10+5+7=31,为所有方案中的最大值。

【输入输出样例 2 说明】

所有路口及适合于修建赛道的道路如下图所示:

需要修建 33条赛道。可以修建如下 33条赛道:

  1. 经过第 1,61,6条道路的赛道(从路口 11 到路口77),长度为 6 + 9 = 156+9=15;
  2. 经过第5,2,3,85,2,3,8 条道路的赛道(从路口66 到路口 99),长度为 4 + 3 + 5 + 4 = 164+3+5+4=16;
  3. 经过第 7,47,4 条道路的赛道(从路口 88 到路口55),长度为 7 + 10 = 177+10=17。 长度最小的赛道长度为 1515,为所有方案中的最大值。

【数据规模与约定】

所有测试数据的范围和特点如下表所示 :

其中,“分支不超过 33”的含义为:每个路口至多有 33 条道路与其相连。 对于所有的数据, 【全是数学写法就不打一遍了QAQ。

题解:

题意就是——给你一棵树,让你找出m条路径使没有边重合的前提下让最短的路径长度尽量长,并输出那个值。

我记住了,看到这种东西让最小值最达化,让最大值最小化的就想到二分答案……

二分枚举最短边的最大长度,条件为能找到m条合法路径。所谓合法路径,就是路径长度二分枚举的长度

那么问题就从让二分的最大长度尽量大 变成了 怎么让合法路径数量尽量多

因为路径都有两种形态——链状 和 对折。对应的也可以说成是——链 和 两条链拼在一起。归根到底都是链。所以——我们就可以维护以u为LCA的最优链的长度。这里的最优是迎合“合法路径数尽量多”的。所谓最多——我们类似于树形dp地dfs下去,回溯时处理:如果有u的某个子节点的到u这里的路径长度满足条件了,那么我们就算是找到一条路径了,直接累加;否则,会剩下很多条半链,我们再考虑拼合到一起。

对于这些不能独立的半链,我们用贪心的思路,先按长度排个序,再头尾搭配得到尽量多的合法折链。也就是“尽量小的和尽量大的合并”。合并完了过后还没完,因为就算是这样合并了,也还是会剩下一些半链的,所以就要让来继承一条最优的半链了。怎么最优呢?当然是长度最长啊!!!所以我们找到一条不影响两两拼合的数量的最长的半链过渡给即可。注意,是不影响答案,如果记录下选的边的编号的话,但凡存在多解的情况就有可能继承过去的不是最优的长度。所以怎么判断不影响呢?继续二分吧……【因为枚举每个儿子的话有可能复杂度会爆掉的,而且因为有独链的存在会导致判定很麻烦】二分选哪个儿子的f值继承过来。

再者就是如何判断不影响?除了你准备继承过去的那个值,在剩下的所有无法独立的半链里再跑一次看看是否能得到和上一段合并半链得到的最大的结果一样的结果,一样则行,否则不行。

至此——这个题就完啦。

【其实我就是看题解代码看懂的QwQ】

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#define maxn 50005
using namespace std;
const int mod = 1e6;
typedef long long ll;
int read() {int x = 0, f = 1, ch = getchar();while(!isdigit(ch)) {if(ch == '-') f = -1; ch = getchar();}while(isdigit(ch)) x = (x << 1) + (x << 3) + ch - '0', ch = getchar();return x * f;
}struct edge {int to, w, nxt;edge() {}edge(int t, int ww, int nn) {to = t, w = ww, nxt = nn;}
}e[maxn << 1];int head[maxn], k = 0;
void add(int u, int v, int w) {e[k] = edge(v, w, head[u]); head[u] = k++;}vector<int> son[maxn];
ll f[maxn], ans;
int recheck(int u, int pos, ll x) {register int l = 0, r = son[u].size() - 1, tot = 0;for(; r >= 0; r--) {if(r == pos) r--;//l和r都避开pos这个位置while(l < r && son[u][l] + son[u][r] < x) l++; if(l == pos) l++;if(l >= r) break;tot++; l++;}return tot;
}void dfs(int u, int fa, ll x) {son[u].clear();for(register int v, i = head[u]; ~i; i = e[i].nxt) {v = e[i].to; if(v == fa) continue;dfs(v, u, x);f[v] += e[i].w;if(f[v] >= x) ans++;else son[u].push_back(f[v]);}sort(son[u].begin(), son[u].end());//son里直接存各个非独立半链的长度register int l = 0, r = son[u].size() - 1, tmp = 0, mid, pos;for(; r >= 0; r--) {//贪心找最大匹配数中while(l < r && son[u][l] + son[u][r] < x) l++;if(l >= r) break; tmp++; l++;//l这里必须++,否则可能会重复加}ans += tmp;//累加答案if((tmp << 1) == son[u].size()) return;//这就说明没有继承的余地了……l = 0; r = son[u].size();//这里r不是size-1了,也是因为我二分的方式原因……while(l < r) {//这样写就挂掉了呢。改成另一种就过了 mid = l + r >> 1;if(recheck(u, mid, x) == tmp) l = mid + 1;//这里tmp还要用的else r = mid;}f[u] = son[u][l - 1];
}int n, m;
bool check(ll mid) {ans = 0; memset(f, 0, sizeof f); dfs(1, 0, mid);//初始化,dfsif(ans >= m) return true; return false;//如果找到了>=m条合法路径,那么这个答案就是可行的
}signed main() {memset(head, -1, sizeof head);n = read(), m = read();register ll l = 0, r = 0, mid;for(register int i = 1, u, v, w; i < n; i++) u = read(), v = read(), w = read(), add(u, v, w), add(v, u, w), r += w;r /= 1ll * m; r++;//这里r++是因为我的二分方式是左闭右开的……所以就被坑害了好久……register long long out;while(l < r) {mid = l + r >> 1;if(check(mid)) l = mid + 1;else r = mid;}printf("%lld\n", l - 1);return 0;
}

控诉一下……二分是真的毒瘤好吧……我真的真的真的记住了这个卡了我一个下午的bug:

前者,区间是左闭右开的;后者,是左右均闭的。所以要这么写效果才能一样啊……

int l = 1; r = 11;
while(l < r) {mid = l + r >> 1;if() l = mid + 1;else r = mid;
} out:l - 1//=============================================================================int pos, l = 1, r = 10;
while(l <= r) {mid = l + r >> 1;if() l = mid + 1, pos = mid;else r = mid - 1;
} out:pos

迎评:)
——End——

NOIP2018·赛道修建相关推荐

  1. NOIP2018D1T3赛道修建

    题目描述 一道让人受益匪浅的树形DP+贪心二分题 C 城将要举办一系列的赛车比赛.在比赛前,需要在城内修建m条赛道. C 城一共有n个路口,这些路口编号为1,2,-,n,有 n-1 条适合于修建赛道的 ...

  2. 【NOIP 2018 提高组】赛道修建

    传送门 problem C 城将要举办一系列的赛车比赛.在比赛前,需要在城内修建 mmm 条赛道. C 城一共有 nnn 个路口,这些路口编号为 1,2,-,n1,2,-,n1,2,-,n,有 n−1 ...

  3. P5021 赛道修建

    题目描述 C 城将要举办一系列的赛车比赛.在比赛前,需要在城内修建 m 条赛道. C 城一共有 n 个路口,这些路口编号为 1,2,-,n,有 n−1条适合于修建赛道的双向通行的道路,每条道路连接着两 ...

  4. 【NOIP2018】赛道修建【二分】【树形dp】【multiset】【贪心】

    传送门 题意:给一棵带边权的树,求MMM条没有公共边的路径的最小长度的最大值. N≤50000N \leq50000N≤50000 抛开NOIP不谈,其实这题本身出的很好 显然二分 问题转化成了&qu ...

  5. noip2018——题解总结

    近期正在疯狂复习某些东西,这篇博客尽量年底更完--(Day2T2除外) 好了,所有的希望都破灭了,原来这就是出题人的素质.--一个被欺骗的可怜 $OIer$ 人生中倒数第三次 $noip$ (Mayb ...

  6. NOIP2018提高组比赛总结

    NOIP2018提高组比赛总结 前言 新赛季,依旧有很多失误. 在些许的遗憾和无奈中,NOIP2018,撒花结束 纵观今年的整一场NOIP,有许多值得总结的地方 正文 NOIP2018初赛 第二次参加 ...

  7. NOIP2018提高组Day1 解题报告

    前言 关于\(NOIP2018\),详见此博客:NOIP2018学军中学游记(11.09~11.11). 这次\(NOIP\ Day1\)的题目听说很简单(毕竟是三道原题),然而我\(T3\)依然悲剧 ...

  8. 【NOIP2018】DAY2T2——填数游戏(轮廓线状压的dp?搜索打表)

    描述 小 D 特别喜欢玩游戏.这一天,他在玩一款填数游戏. 这个填数游戏的棋盘是一个n × m的矩形表格.玩家需要在表格的每个格子中填入一个数字(数字 0 或者数字 1),填数时需要满足一些限制. 下 ...

  9. NOIP2018游记题解

    Day 0 openday,open了一天.和yx,zyh三杀 晚上到了学军旁边的酒店. 看了一下电视睡觉了. Day 1 早上8点到了考场,唯一的感觉是冷. 8点15分进了考场. 700+台笔记本. ...

最新文章

  1. U盘挂载,gedit,vi,文本模式中文乱码等等问题
  2. js 微信小程序日期 时间转时间戳
  3. 第十届蓝桥杯(含题目文件下载)
  4. 盐城工学院计算机基础试卷,大学计算机基础及实用软件/大学计算机基础
  5. 魔法少女小Scarlet(洛谷P4924题题解,C++语言描述)
  6. Veeam虚拟化备份
  7. tensorflow之variables_to_restore
  8. 人生三分之一的睡眠决定着另外三分之二的精彩
  9. WinCE5.0中文模拟器SDK(VS2005)的配置
  10. C++基础--static的用法
  11. oracle拼音匹配,求完整简洁的Oracle获得汉字字符串拼音首字母和全拼的函数
  12. LayoutInflater的使用
  13. 看懂财务报表一资产负债表
  14. 分布式一致性哈希分析
  15. css从中间向两边动画,css动画效果:鼠标移上去底部线条从中间往两边延伸 - 子成君-分享出去,快乐加倍!-旧版已停更...
  16. 小功能⭐️Untiy组合键检测
  17. 卫生事业单位计算机科学与技术,2021年卫生事业单位考试计算机科学与技术知识点-20210417090636.doc-原创力文档...
  18. Windows10 会不会成为微软的新起点?
  19. 如何用python抓取文献_浅谈Python爬虫技术的网页数据抓取与分析
  20. python 0x80070659系统策略禁止这个安装

热门文章

  1. 玩转软路由 篇五:ROS和OpenWRT的软路由方案中IPTV融合教程
  2. Mysql_DML数据修改语言
  3. 计算机网络【1】 TCP/IP
  4. VB.NET的form窗体操作
  5. 将两个有相连关系的数据表进行归类
  6. linux图形框架DRI
  7. ‘svchost.exe-应用程序错误 0xc0000409’客户端无法登陆终端服务器之解决方法
  8. 解读:政务信息资源整合共享难点分析及对策研究
  9. Redis 之 subscribe 订阅模式封装
  10. 云计算-7-Dockerfile深度解析CMD和ENTRYPOINT指令