Problem

Background

公元 \(2044\) 年,人类进入了宇宙纪元。

Description

公元\(2044\) 年,人类进入了宇宙纪元。

$L $国有 \(n\) 个星球,还有 \(n-1\) 条双向航道,每条航道建立在两个星球之间,这 \(n-1\) 条航道连通了 \(L\) 国的所有星球。

小 \(P\) 掌管一家物流公司, 该公司有很多个运输计划,每个运输计划形如:有一艘物流飞船需要从 \(u_i\) 号星球沿最快的宇航路径飞行到 \(v_i\) 号星球去。显然,飞船驶过一条航道是需要时间的,对于航道 \(j\),任意飞船驶过它所花费的时间为 \(t_j\),并且任意两艘飞船之间不会产生任何干扰。

为了鼓励科技创新, \(L\) 国国王同意小 \(P\) 的物流公司参与 \(L\) 国的航道建设,即允许小\(P\) 把某一条航道改造成虫洞,飞船驶过虫洞不消耗时间。

在虫洞的建设完成前小 \(P\) 的物流公司就预接了 \(m\) 个运输计划。在虫洞建设完成后,这 \(m\) 个运输计划会同时开始,所有飞船一起出发。当这 \(m\) 个运输计划都完成时,小 \(P\) 的物流公司的阶段性工作就完成了。

如果小 \(P\) 可以自由选择将哪一条航道改造成虫洞, 试求出小 \(P\) 的物流公司完成阶段性工作所需要的最短时间是多少?

Input Format

第一行包括两个正整数 \(n, m\),表示 \(L\) 国中星球的数量及小 \(P\) 公司预接的运输计划的数量,星球从 \(1\) 到 \(n\) 编号。

接下来 \(n-1\) 行描述航道的建设情况,其中第 \(i\) 行包含三个整数 \(a_i, b_i\) 和 \(t_i\),表示第 \(i\) 条双向航道修建在 \(a_i\) 与 \(b_i\)两个星球之间,任意飞船驶过它所花费的时间为 \(t_i\)。数据保证 \(1 \leq a_i,b_i \leq n\) 且 \(0 \leq t_i \leq 1000\)。

接下来 \(m\) 行描述运输计划的情况,其中第 \(j\) 行包含两个正整数 \(u_j\) 和 \(v_j\),表示第 \(j\) 个运输计划是从 \(u_j\) 号星球飞往 \(v_j\)号星球。数据保证 \(1 \leq u_i,v_i \leq n\)

Output Format

一个整数,表示小 \(P\) 的物流公司完成阶段性工作所需要的最短时间。

Sample

Input

  1. 6 3
  2. 1 2 3
  3. 1 6 4
  4. 3 1 7
  5. 4 3 6
  6. 3 5 5
  7. 3 6
  8. 2 5
  9. 4 5

Output

  1. 11

Range

对于 \(100\%\) 的数据,\(100 \leq n \leq 300000\),\(1 \leq m \leq 300000\)。

Algorithm

二分答案,树上乱搞

Mentality

首先看到题目所求,是求最大值最小化。一下子就发现答案是单调的,那么二分答案就确定了。那么二分之后如何\(check\)呢?

  • 可以发现,当我们二分到一个值\(mid\)时,对于所有小于等于它的路径都无需处理。
  • 对于所有大于\(mid\)的路径,我们所修改的边必定是这些路径所共同覆盖的,否则对于某条未覆盖此边的路径它的值不会改变,仍旧大于等于\(mid\)
  • 在此基础上,修改所有路径共同覆盖的边中权值最大的一定最优。

那么一步步来。

  • 首先是二分,这个肯定没有问题。
  • 那么对于所有大于 mid 的路径,路径从大到小排序确定前缀大于\(mid\)的最靠后位置即可。路径长度可通过记录树上前缀和做到--不难想到,两个端点的树上前缀和之和减去两倍 \(lca\) 的树上前缀和。
  • 如何寻找被共同覆盖的边?
    • 首先引入概念--树上前缀和与子树和。树上前缀和即是记录当前节点 \(i\) 到根结点的距离,子树和则是以 \(i\) 为根结点的子树内所有节点的权值和。
    • 考虑利用子树和进行树上差分。我们将路径的左右端点的用于差分的数组 \(+1\) ,然后如果此时我们统计整棵树所有结点的数组的子树和,我们会神奇地发现,从左端点以及右端点到 \(lca\) 的路径上所有结点的子树和都为 \(1\) ,从 \(lca\) 到根结点的路径上所有结点的子树和都为 \(2\) !那么不难发现,如果我们在 \(lca\) 的上再 \(-1\) ,在 \(lca\) 的父结点上也 \(-1\),再计算一次子树和,就会发现此时这条路径上所有结点的数组子树和都为 \(1\) !也就是说,正好整条路径上的结点都 \(+1\) 了!
    • 只需要稍加修改,一个结点的子树和表示的是它到父结点的边的子树和,接着对于 \(lca\) 我们改为在 \(lca\) 处 \(-2\) 并不对父结点处理即可!
    • 所以差分真是个妙东西(小声bb)。
  • 当对于所有的路径做完差分之后再统一做子树和后,对于每个子树和为大于 \(mid\) 路径总数的点,它到父结点的边一定被这些路径同时经过,对于这些路径,我们取 \(max\) 即可。
  • 至于最长的路径,直接拿最长的路径减去 \(max\) 并判断是否小于等于 \(mid\) 即可。

然后这道题就轻松 A 掉了!

Code

  1. // luogu-judger-enable-o2
  2. // 开O2是因为有个点极度卡人,目前我已知的人里只有用树剖求LCA的过掉了......
  3. #include <algorithm>
  4. #include <cstdio>
  5. #include <cstring>
  6. #include <iostream>
  7. using namespace std;
  8. int n, m, ans int head[300001],
  9. f[300001][20]; // head数组用于链式前向星,f数组为倍增数组
  10. int change[300001], jl[300001],
  11. num[300001]; // change数组为差分数组,jl(就是距离的首字母^_^)数组为树上前缀和,num数组为子树和
  12. struct tree {
  13. int fa, deep;
  14. } k[300001]; //记录树上结点信息
  15. struct node {
  16. int u, v, lenth, lca;
  17. } s[300001]; //路径信息
  18. struct egde {
  19. int next, to, w;
  20. } g[600001]; //边信息
  21. int cmp(node x, node y) { return x.lenth > y.lenth; }
  22. void read(int &x) {
  23. x = 0;
  24. char number = getchar();
  25. while (!isdigit(number)) number = getchar();
  26. while (isdigit(number)) {
  27. x = x * 10 + number - '0';
  28. number = getchar();
  29. }
  30. } //快读
  31. void build(int x) {
  32. book[x] = 1;
  33. for (int p = head[x]; p; p = g[p].next)
  34. if (g[p].to != k[x].fa) {
  35. k[g[p].to].deep = k[x].deep + 1;
  36. k[g[p].to].fa = x;
  37. jl[g[p].to] = jl[x] + g[p].w;
  38. build(g[p].to);
  39. }
  40. } //建树,造出深度,父亲结点,树上前缀和的信息
  41. int dfs(int x) {
  42. book[x] = 1;
  43. num[x] += change[x];
  44. int p = head[x];
  45. while (p) {
  46. if (g[p].to != k[x].fa) num[x] += dfs(g[p].to);
  47. p = g[p].next;
  48. }
  49. return num[x];
  50. } //统计子树和
  51. bool pd(int mid) {
  52. int top = 1;
  53. for (int i = 1; i <= n; i++) {
  54. num[i] = 0;
  55. change[i] = 0;
  56. book[i] = 0;
  57. }
  58. while (s[top].lenth > mid && top <= m) top++; //加入需要处理的路径
  59. top--;
  60. for (int i = 1; i <= top; i++) {
  61. change[s[i].u]++;
  62. change[s[i].v]++;
  63. change[s[i].lca] -= 2;
  64. } //差分数组加减
  65. dfs(1);
  66. int maxx = 0;
  67. for (int i = 1; i <= n; i++)
  68. if (num[i] == top) maxx = max(maxx, jl[i] - jl[k[i].fa]); //取最大值
  69. if (s[1].lenth - maxx <= mid) return true;
  70. return false;
  71. } //判断mid是否可行
  72. int LCA(int a, int b) {
  73. if (k[a].deep > k[b].deep) {
  74. for (int j = 19; j >= 0; j--)
  75. if (k[f[a][j]].deep >= k[b].deep) a = f[a][j];
  76. } else
  77. for (int j = 19; j >= 0; j--)
  78. if (k[f[b][j]].deep >= k[a].deep) b = f[b][j];
  79. for (int j = 19; j >= 0; j--)
  80. if (f[a][j] != f[b][j]) {
  81. a = f[a][j];
  82. b = f[b][j];
  83. }
  84. if (a == b) return a;
  85. return k[a].fa;
  86. } //倍增求lca
  87. int main() {
  88. read(n);
  89. read(m);
  90. int u, v, w;
  91. for (int i = 1; i < n; i++) {
  92. read(u);
  93. read(v);
  94. read(w);
  95. g[i].to = v;
  96. g[i].next = head[u];
  97. head[u] = i;
  98. g[i + n].to = u;
  99. g[i + n].next = head[v];
  100. head[v] = i + n;
  101. g[i].w = g[i + n].w = w;
  102. } //存边
  103. k[1].deep = 1;
  104. build(1);
  105. for (int i = 1; i <= n; i++) f[i][0] = k[i].fa;
  106. for (int j = 1; j <= 19; j++)
  107. for (int i = 1; i <= n; i++)
  108. f[i][j] = f[f[i][j - 1]][j - 1]; //倍增数组处理
  109. for (int i = 1; i <= m; i++) {
  110. read(s[i].u);
  111. read(s[i].v);
  112. s[i].lca = LCA(s[i].u, s[i].v);
  113. s[i].lenth = jl[s[i].u] + jl[s[i].v] - jl[s[i].lca] * 2;
  114. } //处理路径相关信息
  115. sort(s + 1, s + m + 1, cmp);
  116. int l = 1, r = s[1].lenth;
  117. ans = r;
  118. while (l <= r) {
  119. int mid = (l + r) / 2;
  120. if (pd(mid)) {
  121. ans = min(ans, mid);
  122. r = mid - 1;
  123. } else
  124. l = mid + 1;
  125. } //二分答案
  126. cout << ans;
  127. }

【NOIP 2015】Day2 T3 运输计划的更多相关文章

  1. 【NOIP 2015 DAY2 T3】 运输计划 (树链剖分-LCA)

    题目背景 公元 2044 年,人类进入了宇宙纪元. 题目描述 L 国有 n 个星球,还有 n-1 条双向航道,每条航道建立在两个星球之间,这 n-1 条航道连通了 L 国的所有星球. 小 P 掌管一家 ...

  2. NOIP 2015 BZOJ 4326 运输计划 (树链剖分+二分)

    Description 公元 年,人类进入了宇宙纪元. L 国有 n 个星球,还有 n− 条双向航道,每条航道建立在两个星球之间,这 n− 条航道连通了 L 国的所有星球. 小 P 掌管一家物流公司, ...

  3. 【NOIP2015提高组】 Day2 T3 运输计划

    题目描述 L 国有 n 个星球,还有 n-1 条双向航道,每条航道建立在两个星球之间,这 n-1 条航道连通了 L 国的所有星球. 小 P 掌管一家物流公司,该公司有很多个运输计划,每个运输计划形如: ...

  4. 树型大融合——NOIP提高组2015 D1T3 【运输计划】

    下午用一个小时看了一下树上差分,打了个差分模板,A了3题,真的爽! 题目描述: 公元2044 年,人类进入了宇宙纪元. L 国有 n 个星球,还有 n-1 条双向航道,每条航道建立在两个星球之间,这 ...

  5. NOIP 2015 DAY2

    跳石头 题目背景 一年一度的“跳石头”比赛又要开始了! 题目描述 这项比赛将在一条笔直的河道中进行,河道中分布着一些巨大岩石.组委会已经选择好了两块岩石作为比赛起点和终点.在起点和终点之间,有 N 块 ...

  6. NOIP[2015] Day2题解

    问题 A: 跳石头 时间限制: 1 Sec  内存限制: 128 MB 题目描述 一年一度的"跳石头"比赛又要开始了! 这项比赛将在一条笔直的河道中进行,河道中分布着一些巨大岩石. ...

  7. NKOJ 【NOIP2015 Day2】运输计划

    时间限制 : 20000 MS   空间限制 : 262144 KB 评测说明 : 2s,256m 问题描述 公元 2044 年,人类进入了宇宙纪元. L 国有 n 个星球,还有 n−1 条双向航道, ...

  8. 洛谷P2668 斗地主==codevs 4610 斗地主[NOIP 2015 day1 T3]

    P2668 斗地主 326通过 2.6K提交 题目提供者洛谷OnlineJudge 标签搜索/枚举NOIp提高组2015 难度提高+/省选- 提交该题 讨论 题解 记录 最新讨论 出现未知错误是说梗啊 ...

  9. 【NOIP 2013 DAY2 T3】 华容道(spfa)

    题目描述 [问题描述] 小 B 最近迷上了华容道,可是他总是要花很长的时间才能完成一次.于是,他想到用编程来完成华容道:给定一种局面, 华容道是否根本就无法完成,如果能完成, 最少需要多少时间. 小 ...

随机推荐

  1. numpy高级索引

    布尔值索引 name_arr = np.array(["bob","joe","will","bob","jo ...

  2. golang学习笔记9 beego nginx 部署 nginx 反向代理 golang web

    golang学习笔记9 beego nginx 部署 nginx 反向代理 golang web Nginx 部署 - beego: 简约 & 强大并存的 Go 应用框架https://bee ...

  3. java 数组和集合

    1.概念说明 区别:数组固定长度的,集合,数组的长度是可以变化的. List,继承Collection,可重复.有序的对象 Set,继承Collection,不可重复.无序的对象 Map,键值对,提供 ...

  4. Linux下解析域名命令-dig 命令使用详解

    Linux下解析域名除了使用nslookup之外,开可以使用dig命令来解析域名,dig命令可以得到更多的域名信息.dig 命令主要用来从 DNS 域名服务器查询主机地址信息.dig的全称是 (dom ...

  5. codevs——1003——电话连线

    题目描述 Description 一个国家有n个城市.若干个城市之间有电话线连接,现在要增加m条电话线(电话线当然是双向的了),使得任意两个城市之间都直接或间接经过其他城市有电话线连接,你的程序应该能 ...

  6. 关于Android Camera2 API 的自动对焦的坑

    https://www.jianshu.com/p/280e5301b7b9 一.使用.关于Camera2的API使用,参考Google官方的例子: Camera2Basic Camera2Raw C ...

  7. 合并ts到mp4

    这个比较好用. copy /b d:\xxx\download_ts\*   d:\xxx\download_ts\new.mp4 用python ffmpeg也可以,不过我合出来有卡顿或者掉声问题, ...

  8. Prometheus监控学习笔记之PromQL 内置函数

    概述 Prometheus 提供了其它大量的内置函数,可以对时序数据进行丰富的处理.某些函数有默认的参数,例如:year(v=vector(time()) instant-vector).其中参数 v ...

  9. MySql数据库表操作(二)

    一.增加表记录: insert [into] tab_name (field1,field2....) values (values1,values2....) , (values1,values2. ...

  10. android学习:apiDemos导入时R.java无法生成的问题

    准备导入apiDemos研究一下别人的代码,发现导入后不能正常build,无法生成R.java,发现res/layout/progressbar_2.xml里有几个 <ProgressBar a ...