• 动态树的最值


    一 问题描述

    一棵树有 N 个节点,每个节点都有一个权值 Wi ,有 4 种操作。

    ① 1 x y ,在两个节点 x、y 之间添加一条新边。因此,在这种操作之后,两棵树将连接成一棵新树。

    ② 2 x y ,在树集合中找到包含节点 x 的树,并且使节点 x 成为该树的根,然后删除节点 y 与其父节点之间的边。在这种操作之后,一棵树将被分成两部分。

    ③ 3 w x y ,将 x 到 y 路径上所有节点的权值都增加w 。

    ④ 4 x y ,查询 x 到 y 路径上节点的最大权值。

    二 输入和输出

    1 输入

    包含多个测试用例。每个测试用例的第 1 行都包含一个整数 N(1 ≤ N ≤3×10^5 );接下来的 N -1 行,每行都包含两个整数 x、y ,表示它们之间有一条边;下一行包含 N 个整数,表示每个节点的权值都为 Wi(0≤W i ≤3000);再下一行包含一个整数Q(1≤Q≤3×10^5 ),接下来的 Q 行以整数 1、2、3 或 4 为开头,表示操作类型。

    2 输出

    对每个查询,都单行输出正确答案。若此查询是特殊操作,则输出 -1。在每个测试用例之后都输出一个空行。

    三 输入和输出样例

    1 输入样例

    5

    1 2

    2 4

    2 5

    1 3

    1 2 3 4 5

    6

    4 2 3

    2 1 2

    4 2 3

    1 3 5

    3 2 1 4

    4 1 4

    2 输出样例

    3

    -1

    7

    四 注意

    在第 1 种操作中,若节点 x 、y 属于同一棵树,则是特殊的。

    在第 2 种操作中,若x =y 或者x 、y 不属于同一棵树,则是特殊的。

    在第 3 种操作中,若x 、y 不属于同一棵树,则是特殊的。

    在第 4 种操作中,若x 、y 不属于同一棵树,则是特殊的。

    五 分析

    根据输入样例,构建的树形结构如下图所示。

    输入样例的 6 种操作如下。

    (1)4 2 3:查询 2-3 的最大节点权值,输出 3。

    (2)2 1 2:找到包含节点 1 的树,使节点 1 成为该树的根,然后删除节点 2 与其父节点之间的边,实际上就是删除 1-2 的边。

    (3)4 2 3:查询 2-3 的最大节点权值,2、3 不属于同一棵树,是非法的,输出 -1。

    (4)1 3 5:连接 3-5 的边。

    (5)3 2 1 4:将 1-4 路径上的节点权值加 2。

    (6)4 1 4:查询 1-4 的最大节点权值,输出 7。

    六 设计

    本问题包含 4 种基本操作。

    (1)连边:在 x、y 之间连接一条新边,若 x、y 属于同一棵树,则非法,输出 -1;否则执行 link(x , y)。

    (2)删边:删除 x、y 之间的边。若 x=y 或者 x、y 不属于同一棵树,则非法,输出 -1;否则执行 cut(x , y )。

    (3)区间更新:将 x 到 y 路径上所有节点的权值都增加 w 。若节点 x、y 不属于同一棵树,则非法,输出-1;否则执行 addval(x , y ,w )。

    (4)区间最值查询:输出 x 到 y 路径上节点的最大权值。若节点 x、y 不属于同一棵树,则非法,输出-1;否则执行 split(x , y ),输出 mx[y]。

    七 代码

    1. package com.platform.modules.alg.alglib.hdu4010;
    2. public class Hdu4010 {
    3. private int inf = 0x3f3f3f3f;
    4. private int N = 300005;
    5. int n, m, top;
    6. int c[][] = new int[N][2];
    7. int fa[] = new int[N];
    8. int v[] = new int[N];
    9. int st[] = new int[N];
    10. int add[] = new int[N];
    11. int mx[] = new int[N];
    12. int rev[] = new int[N];
    13. void update(int x) {
    14. int l = c[x][0], r = c[x][1];
    15. mx[x] = Math.max(mx[l], mx[r]);
    16. mx[x] = Math.max(mx[x], v[x]);
    17. }
    18. void pushdown(int x) {
    19. int l = c[x][0], r = c[x][1];
    20. if (rev[x] == 1) {
    21. rev[l] ^= 1;
    22. rev[r] ^= 1;
    23. rev[x] ^= 1;
    24. int temp = c[x][0];
    25. c[x][0] = c[x][1];
    26. c[x][1] = temp;
    27. }
    28. if (add[x] > 0) {
    29. if (l > 0) {
    30. add[l] += add[x];
    31. mx[l] += add[x];
    32. v[l] += add[x];
    33. }
    34. if (r > 0) {
    35. add[r] += add[x];
    36. mx[r] += add[x];
    37. v[r] += add[x];
    38. }
    39. add[x] = 0;
    40. }
    41. }
    42. boolean isroot(int x) {
    43. return c[fa[x]][0] != x && c[fa[x]][1] != x;
    44. }
    45. void rotate(int x) {
    46. int y = fa[x], z = fa[y], k;
    47. if (c[y][0] == x) {
    48. k = 1;
    49. } else {
    50. k = 0;
    51. }
    52. if (!isroot(y)) c[z][c[z][1] == y ? 1 : 0] = x;
    53. fa[x] = z;
    54. fa[y] = x;
    55. fa[c[x][k]] = y;
    56. c[y][k == 0 ? 1 : 0] = c[x][k];
    57. c[x][k] = y;
    58. update(y);
    59. update(x);
    60. }
    61. void splay(int x) {
    62. top = 0;
    63. st[++top] = x;
    64. for (int i = x; !isroot(i); i = fa[i])
    65. st[++top] = fa[i];
    66. while (top > 0) pushdown(st[top--]);
    67. while (!isroot(x)) {
    68. int y = fa[x], z = fa[y];
    69. if (!isroot(y)) {
    70. if (c[y][0] == x ^ c[z][0] == y) {
    71. rotate(x);
    72. } else {
    73. rotate(y);
    74. }
    75. }
    76. rotate(x);
    77. }
    78. }
    79. void access(int x) {
    80. for (int t = 0; x > 0; t = x, x = fa[x]) {
    81. splay(x);
    82. c[x][1] = t;
    83. update(x);
    84. }
    85. }
    86. void makeroot(int x) {
    87. access(x);
    88. splay(x);
    89. rev[x] ^= 1;
    90. }
    91. void link(int x, int y) {
    92. makeroot(x);
    93. fa[x] = y;
    94. }
    95. void split(int x, int y) {
    96. makeroot(x);
    97. access(y);
    98. splay(y);
    99. }
    100. void cut(int x, int y) {
    101. split(x, y);
    102. c[y][0] = fa[c[y][0]] = 0;
    103. update(y);
    104. }
    105. int findroot(int x) {
    106. access(x);
    107. splay(x);
    108. while (c[x][0] > 0) x = c[x][0];
    109. return x;
    110. }
    111. void addval(int x, int y, int val) {
    112. split(x, y);
    113. add[y] += val;
    114. mx[y] += val;
    115. v[y] += val;
    116. }
    117. public String output = "";
    118. public String cal(String input) {
    119. int opt, x, y, w;
    120. String[] line = input.split("\n");
    121. n = Integer.parseInt(line[0]);
    122. for (int i = 0; i <= n; i++)
    123. add[i] = rev[i] = fa[i] = c[i][0] = c[i][1] = 0;
    124. mx[0] = -inf;
    125. for (int i = 1; i < n; i++) {
    126. String[] num = line[i].split(" ");
    127. x = Integer.parseInt(num[0]);
    128. y = Integer.parseInt(num[1]);
    129. link(x, y);
    130. }
    131. String[] wi = line[n].split(" ");
    132. for (int i = 1; i <= n; i++) {
    133. v[i] = Integer.parseInt(wi[i - 1]);
    134. mx[i] = v[i];
    135. }
    136. m = Integer.parseInt(line[n + 1]);
    137. int count = 0;
    138. while (m-- > 0) {
    139. String[] query = line[n + 2 + count++].split(" ");
    140. opt = Integer.parseInt(query[0]);
    141. x = Integer.parseInt(query[1]);
    142. y = Integer.parseInt(query[2]);
    143. switch (opt) {
    144. case 1:
    145. if (findroot(x) == findroot(y)) {
    146. output += "-1\n";
    147. break;
    148. }
    149. link(x, y);
    150. break;
    151. case 2:
    152. if (findroot(x) != findroot(y) || x == y) {
    153. output += "-1\n";
    154. break;
    155. }
    156. cut(x, y);
    157. break;
    158. case 3:
    159. w = x;
    160. x = y;
    161. y = Integer.parseInt(query[3]);
    162. if (findroot(x) != findroot(y)) {
    163. output += "-1\n";
    164. break;
    165. }
    166. addval(x, y, w);
    167. break;
    168. case 4:
    169. if (findroot(x) != findroot(y)) {
    170. output += "-1\n";
    171. break;
    172. }
    173. split(x, y);
    174. output += mx[y] + "\n";
    175. break;
    176. }
    177. }
    178. return output;
    179. }
    180. }

    八 测试

  • 相关阅读:
    深入理解final关键字
    辅助驾驶功能开发-功能对标篇(2)-NGP领航辅助系统-小鹏
    mysql8.0英文OCP考试第141-150题
    Javaweb重要知识点总结(六)常见的前端框架
    开发基于 ChatGPT 分析热点事件并生成文章的网站应用【热点问天】把百度等热点用chatGPT来对热点事件分析海量发文章 开发步骤 多种方式获取利润
    Prometheus - 系统监控与警报管理
    【深度学习】实验6答案:图像自然语言描述生成(让计算机“看图说话”)
    离线语音识别PocketSphinx(一)
    NodeJS连接MongoDB数据库(数据校验,增删查改)
    shigen的一些shell脚本分享
  • 原文地址:https://blog.csdn.net/chengqiuming/article/details/127880588