あいさか たいがblogAisaka_Taiga的博客
//https://img2018.cnblogs.com/blog/1646268/201908/1646268-20190806114008215-138720377.jpg

NOIP2018 赛道修建

Toretto·2023-10-29 16:38·13 次阅读

NOIP2018 赛道修建

观察题目不难想到二分答案。

考虑二分所有赛道的最小长度值,那么我们可以去判断最后修建出来的赛道数是不是大于等于 m 条即可。

fi 表示当前以 i 为根,最长的未被赛道占用的链的长度。

但是有很多链,匹配的过程不好进行,所以改为用 multiset 来维护当前点的链有多少个没匹配的。

在处理完所有子树后,对 mltiset 内的元素分以下几种情况讨论:

  • 当前 set 内只有一个元素,直接退出,当前点最长未匹配的就是他。

  • 当前 set 内有多个,那么取最小值,然后看 set 里是否有元素和他加起来能到 mid,如果可以就 sum++,反之删除,然后更新最大未匹配的链长。

  • 有一个特殊情况就是当前单条链就大于等于 mid 了,可以直接不加进 set 里。

Copy
/* * @Author: Aisaka_Taiga * @Date: 2023-10-29 15:17:24 * @LastEditTime: 2023-10-29 16:27:11 * @LastEditors: Aisaka_Taiga * @FilePath: \Desktop\P5021.cpp * The heart is higher than the sky, and life is thinner than paper. */ #include <bits/stdc++.h> #define int long long #define N 50100 using namespace std; inline int read() { int x = 0, f = 1; char c = getchar(); while(c < '0' || c > '9'){if(c == '0') f = -1; c = getchar();} while(c <= '9' && c >= '0') x = (x << 1) + (x << 3) + (c ^ 48), c = getchar(); return x * f; } int n, m, head[N << 1], cnt, ans, sum, mid; struct node{int u, v, w, next;}e[N << 1]; multiset<int> s[N]; multiset<int> :: iterator it; inline void add(int u, int v, int w){e[++ cnt] = (node){u, v, w, head[u]}; head[u] = cnt;} inline int dfs(int x, int fa) { s[x].clear();//每次都清空一下 for(int i = head[x]; i; i = e[i].next) { int v = e[i].v; if(v == fa) continue; int val = e[i].w + dfs(v, x);//当前子树通过这条道路能到x点的长度 if(val >= mid) sum ++;//直接大于mid了就归成一条赛道,条数加1 else s[x].insert(val);//否则就插入当前点的set里 } int res = 0;//存放当前点能到达x点的最短的路径长度 while(!s[x].empty()) { if(s[x].size() == 1) return max(res, *s[x].begin());//只有一个就没有可以选的直接返回第一个 int kk = *s[x].begin();//当前最小的元素的值 s[x].erase(s[x].begin());//删除 it = s[x].lower_bound(mid - kk);//找到当前子树里最小的差多少 if(it == s[x].end()) res = max(res, kk);//找不到加起来能到mid的就更新没匹配的最大值 else sum ++, s[x].erase(it);//能匹配上就赛道数+1,删除当前的长度 } return res; } inline int check() { sum = 0;//存放当前mid长度能分出来的赛道条数 dfs(1, 0); return sum >= m; } signed main() { n = read(), m = read(); for(int i = 1; i <= n - 1; i ++) { int u = read(), v = read(), w = read(); add(u, v, w), add(v, u, w); } int l = 1, r = 1e9; while(l < r) { mid = (l + r) >> 1; if(check()) l = mid + 1; else r = mid; } cout << l - 1 << endl; return 0; } /* 7 1 1 2 10 1 3 5 2 4 9 2 5 8 3 6 6 3 7 7 */
posted @   北烛青澜  阅读(13)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
点击右上角即可分享
微信分享提示