题目链接

传送门

题意

两个绝顶聪明的人在树上玩博弈,规则是轮流选择下一个要到达的点,每达到一个点时,先手和后手分别获得\(a_i,b_i\)(到达这个点时两个人都会获得)的权值,已经经过的点无法再次经过,直到无法移动则结束游戏,两人都想最大化自己的权值和减对手权值和,问先手减后手权值和最大是多少。

思路

换根\(DP\),和求树的直径有点类似。

\(dp[i][j]\)表示在\(i\)这个结点状态为\(j\)时先手权值和减后手权值和最优是多少,\(j\)为偶数表示当前是先手,为奇数时为后手。

转移方程:我们该\(dp\)是倒着推的,也就是说从游戏结束开始往游戏开始推,假设当前是先手选择,那么下一步就是后手移动,按照题目要求后手一定是想最小化先手减后手权值和,因此当前一定是从最小的先手减后手权值和转移过来;如果当前是后手那么就从先手减后手权值和最大转移过来。

需要特别注意的两点是:

  • 从子结点转移过来很好想,就是子结点中相反状态转移过来,也就是当前为先手那么从最小过来;从父亲结点转移过来的时候,因为一个结点只有一个父亲结点,因此如果当前是先手,那么父亲结点也就确定了,因此它要从父亲结点从其他结点转移过来的最大值转移到当前结点,后手同理,枚举起点时由于你枚举之后起点也固定了,因此对于同一个起点要选择值最小的方向(因为这里我卡了好久,好菜啊)。

  • 最后枚举答案的时候如果当前点是叶子结点,那么它的答案是从父亲结点贡献的,不能由它自己贡献,因为如果先手选择这个点为起点,那么后手一定是往父亲结点选。

代码

  1. #include <set>
  2. #include <map>
  3. #include <deque>
  4. #include <queue>
  5. #include <stack>
  6. #include <cmath>
  7. #include <ctime>
  8. #include <bitset>
  9. #include <cstdio>
  10. #include <string>
  11. #include <vector>
  12. #include <cassert>
  13. #include <cstdlib>
  14. #include <cstring>
  15. #include <iostream>
  16. #include <algorithm>
  17. using namespace std;
  18. typedef long long LL;
  19. typedef pair<LL, LL> pLL;
  20. typedef pair<LL, int> pLi;
  21. typedef pair<int, LL> pil;;
  22. typedef pair<int, int> pii;
  23. typedef unsigned long long uLL;
  24. #define lson (rt<<1),L,mid
  25. #define rson (rt<<1|1),mid + 1,R
  26. #define lowbit(x) x&(-x)
  27. #define name2str(name) (#name)
  28. #define bug printf("*********\n")
  29. #define debug(x) cout<<#x"=["<<x<<"]" <<endl
  30. #define FIN freopen("/home/dillonh/CLionProjects/Dillonh/in.txt","r",stdin)
  31. #define IO ios::sync_with_stdio(false),cin.tie(0)
  32. const double eps = 1e-8;
  33. const int mod = 1000000007;
  34. const int maxn = 100000 + 7;
  35. const double pi = acos(-1);
  36. const int inf = 0x3f3f3f3f;
  37. const LL INF = 0x3f3f3f3f3f3f3f3fLL;
  38. int t, n, tot, x, u, v;
  39. int a[maxn], head[maxn], du[maxn];
  40. LL dp[maxn][6];
  41. struct edge{
  42. int v, next;
  43. }ed[maxn*2];
  44. void add(int u, int v) {
  45. ed[tot].v = v;
  46. ed[tot].next = head[u];
  47. head[u] = tot++;
  48. }
  49. void dfs1(int u, int p) {
  50. for(int i = head[u]; ~i; i = ed[i].next) {
  51. int v = ed[i].v;
  52. if(v == p) continue;
  53. dfs1(v, u);
  54. ++du[u];
  55. if(dp[v][1] < dp[u][0]) {
  56. dp[u][2] = dp[u][0];
  57. dp[u][0] = dp[v][1];
  58. } else {
  59. dp[u][2] = min(dp[u][2], dp[v][1]);
  60. }
  61. if(dp[v][0] > dp[u][1]) {
  62. dp[u][3] = dp[u][1];
  63. dp[u][1] = dp[v][0];
  64. } else {
  65. dp[u][3] = max(dp[u][3], dp[v][0]);
  66. }
  67. }
  68. if(dp[u][0] == INF) dp[u][0] = dp[u][1] = dp[u][2] = dp[u][3] = 0;
  69. dp[u][0] += a[u], dp[u][2] += a[u];
  70. dp[u][1] += a[u], dp[u][3] += a[u];
  71. }
  72. void dfs2(int u, int p) {
  73. for(int i = head[u]; ~i; i = ed[i].next) {
  74. int v = ed[i].v;
  75. if(v == p) continue;
  76. if(du[u] == 1) {
  77. dp[v][5] = dp[u][4] + a[v];
  78. dp[v][4] = dp[u][5] + a[v];
  79. } else {
  80. if(dp[u][0] == dp[v][1] + a[u]) {
  81. if(u != 1) dp[v][5] = min(dp[u][2], dp[u][4]) + a[v];
  82. else dp[v][5] = dp[u][2] + a[v];
  83. } else {
  84. if(u != 1) dp[v][5] = min(dp[u][0], dp[u][4]) + a[v];
  85. else dp[v][5] = dp[u][0] + a[v];
  86. }
  87. if(dp[u][1] == dp[v][0] + a[u]) {
  88. if(u != 1) dp[v][4] = max(dp[u][3], dp[u][5]) + a[v];
  89. else dp[v][4] = dp[u][3] + a[v];
  90. } else {
  91. if(u != 1) dp[v][4] = max(dp[u][1], dp[u][5]) + a[v];
  92. else dp[v][4] = dp[u][1] + a[v];
  93. }
  94. }
  95. dfs2(v, u);
  96. }
  97. }
  98. int main() {
  99. #ifndef ONLINE_JUDGE
  100. FIN;
  101. #endif
  102. scanf("%d", &t);
  103. while(t--) {
  104. scanf("%d", &n);
  105. tot = 0;
  106. for(int i = 1; i <= n; ++i) {
  107. scanf("%d", &a[i]);
  108. head[i] = -1;
  109. du[i] = 0;
  110. dp[i][0] = dp[i][2] = dp[i][4] = INF;
  111. dp[i][1] = dp[i][3] = dp[i][5] = -INF;
  112. }
  113. for(int i = 1; i <= n; ++i) {
  114. scanf("%d", &x);
  115. a[i] -= x;
  116. }
  117. for(int i = 1; i < n; ++i) {
  118. scanf("%d%d", &u, &v);
  119. add(u, v), add(v, u);
  120. }
  121. dfs1(1, 0);
  122. dp[1][4] = dp[1][5] = a[1];
  123. dfs2(1, 0);
  124. LL ans = dp[1][0];
  125. for(int i = 2; i <= n; ++i) {
  126. if(du[i] == 0) ans = max(ans, dp[i][4]);
  127. else ans = max(ans, min(dp[i][4], dp[i][0]));
  128. }
  129. printf("%lld\n", ans);
  130. }
  131. return 0;
  132. }

Acesrc and Travel(2019年杭电多校第八场06+HDU6662+换根dp)的更多相关文章

  1. Make Rounddog Happy(2019年杭电多校第十场1011+HDU6701+启发式分治)

    目录 题目链接 题意 思路 代码 题目链接 传送门 题意 求有多少个子区间满足\(a_l,a_{l+1},\dots,a_r\)均不相同且\(max(a_l,a_{l+1},\dots,a_r)-(r ...

  2. 2019年杭电多校第三场 1008题Game(HDU6610+带修改莫队+Nim博弈)

    题目链接 传送门 题意 给你\(n\)堆石子,每堆有\(a_i\)堆石子,\(q\)次操作: 在\([L,R]\)内有多少个子区间使得\(Alice\)(先手)在\(Nim\)博弈中获胜: 交换\(a ...

  3. 2019年杭电多校第三场 1011题Squrirrel(HDU6613+树DP)

    题目链接 传送门 题意 给你一棵无根树,要你寻找一个根节点使得在将一条边权变为\(0\)后,离树根最远的点到根节点的距离最小. 思路 本题和求树的直径很像,不过要记得的东西有点多,且状态也很多. \( ...

  4. 2019 杭电多校第八场 HDU - 6665 Calabash and Landlord 两矩形分平面

    题意 给出两个矩形,问这两个矩形把平面分成了几部分. 分析 不需要什么高级技能,只需 “简单” 的分类讨论. (实在太难写了,对拍找出错误都不想改 推荐博客,其中有个很好的思路,即只讨论答案为2,3, ...

  5. [2019杭电多校第八场][hdu6667]Roundgod and Milk Tea

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6667 题目大意是说n个班级,每个班级有ai人和bi杯茶,每个人只能喝其他班的茶并且只能喝一杯.问最多有 ...

  6. 杭电多校第八场-A-Character Encoding

    题目描述 In computer science, a character is a letter, a digit, a punctuation mark or some other similar ...

  7. 2018杭电多校第三场1003(状态压缩DP)

    #include<bits/stdc++.h>using namespace std;const int mod =1e9+7;int dp[1<<10];int cnt[1& ...

  8. 可持久化线段树的学习(区间第k大和查询历史版本的数据)(杭电多校赛第二场1011)

    以前我们学习了线段树可以知道,线段树的每一个节点都储存的是一段区间,所以线段树可以做简单的区间查询,更改等简单的操作. 而后面再做有些题目,就可能会碰到一种回退的操作.这里的回退是指回到未做各种操作之 ...

  9. Rikka with Travels(2019年杭电多校第九场07题+HDU6686+树形dp)

    目录 题目链接 题意 思路 代码 题目链接 传送门 题意 定义\(L(a,b)\)为结点\(a\)到结点\(b\)的路径上的结点数,问有种\(pair(L(a,b),L(c,d))\)取值,其中结点\ ...

随机推荐

  1. [LeetCode] 1028. Recover a Tree From Preorder Traversal 从先序遍历还原二叉树

    We run a preorder depth first search on the rootof a binary tree. At each node in this traversal, we ...

  2. win10安装docker并结合Idea2018.1部署springboot项目

    一.准备工作 1..工具:win10,idea2018,maven3.5,jdk8 二.win10安装docker 1.win10安装docker:http://www.runoob.com/dock ...

  3. node 读取超大Excel 文件,提取数据

    之前是用 node-xlsx 来处理excel文件,主要是读取数据或者根据数据生成excel文件.不过,node-xlsx 似乎无法处理超大的excel(100MB以上),例如: var xlsx = ...

  4. Java学习清单

    转自: csdn/zuochao_2013/article/details/76795164   ·   Java基础部分 *Java基础才是重中之重,只有基础打牢了,学习各种框架才能游刃有余. 1, ...

  5. Idea java 中导包路径分析

    工具类所在包: 查看工具类详情: 调用这个工具类时,导入的包路径为: 路径就是第1张图片中的包名utils+类名NumberUtils组成的utils.NumberUtils

  6. 局域网Linux机器中病毒简单处理 .aliyun.sh 挖矿病毒 ---不彻底

    1. 昨天晚上同事打电话给我说自己的服务器上面的redis无故被清空了,并且查看aof 日志有很多 wget和write指令 一想就是大事不好.局域网中病毒了.. 2. 今天早上到公司忙完一阵简单看了 ...

  7. vCenter6.7的简单安装与使用

    1.VMware的vCenter已经有了很大的改进,安装过程极为简单方便. 2. 下载vCenter的安装包即可. 我这边下载的ISO为: VMware-VIM-all--.iso 网上有资源,通过百 ...

  8. service的yaml说明

    apiVersion: v1 kind: Service metadata: name: nginx-service labels: app: nginx spec: ports: - port: 8 ...

  9. HTML5新标签和CSS伪类

    HTML5提供了很多新的标签,由于HTML5的兼容性比较差,HTML5的标签常用于手机端 <nav> <footer> <section> <header&g ...

  10. Java中关于位运算的面试题

    位运算的效率是最高的,因为位位运算是直接对二进制进行操作 位运算只能应用于整型和char类型(char类型可以看做是特殊的无符号的整形) 面试题: a: 判断一个数是否是奇数 a & 1 == ...