题目链接

problem

给出一棵有边权的树。一条链的权值定义为该链所经过的边的边权值和。需要选出\(m\)条链,求\(m\)条链中权值最小的链的权值最大是多少。

solution

首先显然二分。

然后考虑如何判断二分出来的一个答案\(x\)是否是可行的。也就是能否选出\(m\)条链,每条链权值都大于等于\(x\)。这个其实是贪心。

定义直链为从一个某个点的祖先到该点的路径。

可以发现每条链要么就是一条直链,要么由两条直链在某个点处合并起来得到。

贪心的地方在于,对于每个点肯定都是优先将能合成的直链合成。然后再保证向上传递的直链长度最大。因为即便向上传递的长度特别大,产生的贡献也做多只能是\(1\)。所以要先保证在当前子树上合成最多的链。

然后问题就变成了在一棵子树内得到一些直链长度。现在把这些直链两两合并成权值大于等于\(x\)的链。然后保证剩下的直链长度最大。

这里可以二分答案一下。也可以用个\(multiset\)处理。反正是很可做的一个问题。

代码中有各档部分分,BF5为正解

code

  1. #include<set>
  2. #include<cstdio>
  3. #include<iostream>
  4. #include<cstdlib>
  5. #include<ctime>
  6. #include<algorithm>
  7. #include<queue>
  8. #include<cstring>
  9. using namespace std;
  10. typedef long long ll;
  11. const int N = 100010;
  12. ll read() {
  13. ll x = 0,f = 1;char c = getchar();
  14. while(c < '0' || c > '9') {
  15. if(c == '-') f = -1;
  16. c = getchar();
  17. }
  18. while(c >= '0' && c <= '9') {
  19. x = x * 10 + c - '0';
  20. c = getchar();
  21. }
  22. return x * f;
  23. }
  24. int n,m;
  25. struct node {
  26. int v,nxt,w;
  27. }e[N << 1];
  28. int head[N],ejs;
  29. void add(int u,int v,int w) {
  30. e[++ejs].v = v;e[ejs].nxt = head[u];head[u] = ejs;e[ejs].w = w;
  31. }
  32. namespace BF1 {
  33. int dis[N];
  34. void dfs(int u,int fa) {
  35. for(int i = head[u];i;i = e[i].nxt) {
  36. int v = e[i].v;
  37. if(v == fa) continue;
  38. dis[v] = dis[u] + e[i].w;
  39. dfs(v,u);
  40. }
  41. }
  42. void main() {
  43. dfs(1,0);
  44. int x = 0;
  45. for(int i = 1;i <= n;++i) if(dis[i] > dis[x]) x = i;
  46. // cout<<x<<endl;
  47. memset(dis,0,sizeof(dis));
  48. dfs(x,0);
  49. int ans = 0;
  50. for(int i = 1;i <= n;++i) ans = max(ans,dis[i]);
  51. cout<<ans;
  52. }
  53. }
  54. namespace BF2 {
  55. int a[N],cnt;
  56. int check(int x) {
  57. int p = 1,ret = 0;
  58. for(int i = cnt;i > p;--i) {
  59. if(a[i] > x && i > p) {ret++;continue;}
  60. while(a[p] + a[i] < x && p < i) ++p;
  61. if(p < i) ret++,p++;
  62. else break;
  63. }
  64. return ret;
  65. }
  66. void main() {
  67. int l = 100000,r = 0;
  68. for(int i = 1;i <= ejs;i += 2) a[++cnt] = e[i].w,l = min(l,a[cnt]),r += a[cnt];
  69. sort(a + 1,a + cnt + 1);
  70. int ans = 0;
  71. while(l <= r) {
  72. int mid = (l + r) >> 1;
  73. if(check(mid) >= m) ans = mid,l = mid + 1;
  74. else r = mid - 1;
  75. }
  76. cout<<ans<<endl;
  77. }
  78. }
  79. int du[N];
  80. namespace BF3 {
  81. int a[N],cnt;
  82. void dfs(int u,int fa) {
  83. for(int i = head[u];i;i = e[i].nxt) {
  84. int v = e[i].v;
  85. if(v == fa) continue;
  86. a[++cnt] = e[i].w;
  87. dfs(v,u);
  88. }
  89. }
  90. int check(int x) {
  91. int now = 0,ret = 0;
  92. for(int i = 1;i <= cnt;++i) {
  93. now += a[i];
  94. if(now >= x) now = 0,ret ++;
  95. }
  96. return ret;
  97. }
  98. void main() {
  99. for(int i = 1;i <= n;++i)
  100. if(du[i] == 1) {dfs(i,0);break;}
  101. int l = 1000000,r = 0;
  102. for(int i = 1;i <= ejs;i += 2) {
  103. l = min(l,e[i].w);r += e[i].w;
  104. }
  105. int ans = 0;
  106. while(l <= r) {
  107. int mid = (l + r) >> 1;
  108. if(check(mid) >= m) ans = mid,l = mid + 1;
  109. else r = mid - 1;
  110. }
  111. cout<<ans<<endl;
  112. }
  113. }
  114. int L = 100000,R;
  115. namespace BF5 {
  116. int ANS;
  117. int dfs(int u,int fa,int x) {
  118. multiset<int>s;
  119. int ret = 0;
  120. // if(!s.empty()) printf("%d\n",u);
  121. for(int i = head[u];i;i = e[i].nxt) {
  122. int v = e[i].v;
  123. if(v == fa) continue;
  124. int k = dfs(v,u,x);
  125. if(k + e[i].w >= x) ANS++;
  126. else s.insert(k + e[i].w);
  127. }
  128. while(!s.empty()) {
  129. multiset<int>::iterator it = s.begin();
  130. int k = *it;
  131. s.erase(it);
  132. multiset<int>::iterator is = s.lower_bound(x - k);
  133. if(is == s.end()) ret = max(ret,k);
  134. else ANS++,s.erase(is);
  135. }
  136. // s.clear();
  137. // printf("%d %d\n",u,ret);
  138. return ret;
  139. }
  140. void main() {
  141. int l = L,r = R,ans = 0;
  142. while(l <= r) {
  143. int mid =(l + r) >> 1;
  144. ANS = 0;dfs(1,0,mid);
  145. if(ANS >= m) ans = mid,l = mid + 1;
  146. else r = mid - 1;
  147. }
  148. cout<<ans;
  149. }
  150. }
  151. int main() {
  152. n = read(),m = read();
  153. int bz1 = 1,bz2 = 1;
  154. for(int i = 1;i < n;++i) {
  155. int u = read(),v = read(),w = read();
  156. L = min(L,w);R += w;
  157. du[u]++;du[v]++;
  158. add(u,v,w);add(v,u,w);
  159. if(u != 1) bz1 = 0;
  160. if(v != u + 1) bz2 = 0;
  161. }
  162. if(m == 1) {BF1::main();return 0;}
  163. if(bz1) {BF2::main();return 0;}
  164. if(bz2) {BF3::main();return 0;}
  165. BF5::main();
  166. return 0;
  167. }
  168. /*
  169. 7 1
  170. 1 2 10
  171. 1 3 5
  172. 2 4 9
  173. 2 5 8
  174. 3 6 6
  175. 3 7 7
  176. */

Noip2018Day1T3 赛道修建的更多相关文章

  1. Luogu5021 [NOIP2018]赛道修建

    Luogu5021 [NOIP2018]赛道修建 一棵大小为 \(n\) 的树,边带权.选 \(m\) 条链使得长度和最小的链最大. \(m<n\leq5\times10^4\) 贪心,二分答案 ...

  2. [NOIp2018提高组]赛道修建

    [NOIp2018提高组]赛道修建 题目大意: 给你一棵\(n(n\le5\times10^4)\)个结点的树,从中找出\(m\)个没有公共边的路径,使得第\(m\)长的路径最长.问第\(m\)长的路 ...

  3. noip2018 D1T3 赛道修建

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

  4. noip 2018 D1T3 赛道修建

    noip 2018 D1T3 赛道修建 首先考虑二分答案,这时需要的就是对于一个长度求出能在树中选出来的最多的路径条数.考虑到一条路径是由一条向上的路径与一条向下的路径构成,或者仅仅是向上或向下的路径 ...

  5. 【LG5021】[NOIP2018]赛道修建

    [LG5021][NOIP2018]赛道修建 题面 洛谷 题解 NOIP之前做过增强版还没做出来\(QAQ\) 一看到题目中的最大值最小,就很容易想到二分答案 重点是考虑如何\(check\) 设\( ...

  6. 【noip2018】【luogu5021】赛道修建

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

  7. 竞赛题解 - NOIP2018 赛道修建

    \(\mathcal {NOIP2018}\) 赛道修建 - 竞赛题解 额--考试的时候大概猜到正解,但是时间不够了,不敢写,就写了骗分QwQ 现在把坑填好了~ 题目 (Copy from 洛谷) 题 ...

  8. [NOIP2018TG]赛道修建

    [NOIP2018TG]赛道修建 考场上multiset调不出啊啊啊!!! 首先肯定是二分答案 做树形dp,f[i]表示i点的子树两两匹配后剩下的最长长度 匹配可以用multiset维护 但是菊花图跑 ...

  9. 【题解】 P5021赛道修建

    [题解]P5021 赛道修建 二分加贪心,轻松拿省一(我没有QAQ) 题干有提示: 输出格式: 输出共一行,包含一个整数,表示长度最小的赛道长度的最大值. 注意到没,最小的最大值,还要多明显? 那么我 ...

随机推荐

  1. 使用gitolite搭建Git服务器

    使用gitolite搭建Git服务器 运行环境 Ubuntu18.04 gitolite 搭建过程 安装好Ubuntu18.04系统 更新系统 sudo apt update sudo apt upg ...

  2. SQL Server重建索引与重组索引会更新统计信息吗?

    在SQL Server中重建索引(Rebuild Index)与重组索引(Reorganize Index)会触发统计信息更新吗? 那么我们先来测试.验证一下: 我们以AdventureWorks20 ...

  3. 解读并加工BeautifulReport 报告模板

    使用unittest框架的脚本执行完成后,会生成一个html格式的报告 这个报告是提前制作了一个html的模板,然后将对应的内容写入到模板中,并生成一个最终的报告,这个报告模板在通过 pip inst ...

  4. LeetCode刷题--整数反转(简单)

    题目描述 给出一个 32 位的有符号整数,你需要将这个整数中每位上的数字进行反转. 示例 1: 输入: 123 输出: 321 示例 2: 输入: -123 输出: -321 示例 3: 输入: 12 ...

  5. vue.set( target, key, value ) this.$set(对象获数组,要更改的具体数据,重新赋值)用法

    调用方法:Vue.set( target, key, value ) target:要更改的数据源(可以是对象或者数组) key:要更改的具体数据 value :重新赋的值 具体用法js代码: //设 ...

  6. RTP Payload Format for VP8 Video

    整体结构 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+ ...

  7. 07. Go 语言接口

    Go 语言接口 接口本身是调用方和实现方均需要遵守的一种协议,大家按照统一的方法命名参数类型和数量来协调逻辑处理的过程. Go 语言中使用组合实现对象特性的描述.对象的内部使用结构体内嵌组合对象应该具 ...

  8. 一篇文章看懂angularjs component组件

     壹 ❀ 引 我在 angularjs 一篇文章看懂自定义指令directive 一文中详细介绍了directive基本用法与完整属性介绍.directive是个很神奇的存在,你可以不设置templa ...

  9. VS2010到VS2019各个版本的密钥

    VS2019专业版和企业版的密钥 Visual Studio 2019 EnterpriseBF8Y8-GN2QH-T84XB-QVY3B-RC4DF Visual Studio 2019 Profe ...

  10. MyBatis框架之第二篇

    1.高级参数映射和返回值映射(重点) a)Pojo包装pojo的参数映射 b)当结果集列名与pojo属性名不一致的返回值映射 2.动态sql(重点) 3.关联查询结果(重点) a)一对一关联结果 b) ...