经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » C++ » 查看文章
[C++]P5024 树形DP 保卫王国
来源:cnblogs  作者:Rosyr  时间:2021/3/29 9:14:41  对本文有异议

树形DP 保卫王国P5024

前置知识

1、邻接表 + Dfs(深度优先搜索)

2、基础DP(如 01背包 )

3、最小公共祖先(LCA)

  • LCA我有写过Blog

首先解读一下题意

城市即为节点

每个节点都有一个驻军资金 即节点的权值

现在要让每两个节点之间至少有一个节点拥有驻军

并给出 m 个要求
求出每个要求所对应的最小花费

为了更好的阅读体验

  • 三个方法的完整代码将放在文章最后
  • 请先大致浏览完完整代码再阅读解释
  • 请配合草稿本画图并记录变量名含义

无优化 44分

解题方法

树形DP

顾名思义 是在树形结构中使用动态规划

DP是一种暴力算法

因此把每个节点取与不取的子树最小权值都算出来

就可在根上算出答案

算法评估

由于有多个要求

因此有几个要求 dfs就会执行几次

这导致运行时间大大变长

由于44分代码比较简单 所以就直接把注释打入代码了

部分优化 68分

解题方法

现在我们要想办法解决重复执行的问题

我们可以通过一个预处理来把他们之间之外的算出来

这样就可以大大提升运算速度

下半部分的红色我们已经搞定了

就和无优化部分的一样 处理出 \(f[i][0/1]\) 即可

而对于 \(ff[i][0/1]\) 就要用从上往下的Dfs来解决了 具体看代码

求ff

  1. void dfs2(int u,int fa){
  2. for(int i = head[u];i;i = e[i].u){
  3. int ev = e[i].v;
  4. if(ev == fa) continue;
  5. ff[ev][0] = ff[u][1] + f[u][1] - min(f[ev][0],f[ev][1]);
  6. ff[ev][1] = min(ff[u][0] + f[u][0] - f[ev][1],ff[ev][0]);
  7. dfs2(ev,u);
  8. }
  9. }

主要来看看这两个状态转移方程

\(ff[ev][0]\) :既然ev为0(不可取) 则u必须为1(可取)

\(f[ev][1]\) :ev为0(取) 则u为0/1皆可

所以求出\(ff[ev][0/1]\)通过以上两个方程即可

tushi-2.jpg

可以看到Dfs2的调用被放在了状态转移方程的下面

因为这个Dfs是自上而下的 所以在上面处理完后再进行下面的调用

关于trans函数

  1. void trans(int id){
  2. int a = rest[id].node1;
  3. int b = rest[id].node2;
  4. int x = rest[id].val1;
  5. int y = rest[id].val2;
  6. memset(dp,sizeof(dp),0);
  7. if(x == 0){
  8. dp[a][0] = f[a][0];
  9. dp[a][1] = INF;
  10. } else {
  11. dp[a][1] = f[a][1];
  12. dp[a][0] = INF;
  13. }
  14. if(y == 0){
  15. dp[b][0] = f[b][0];
  16. dp[b][1] = INF;
  17. } else {
  18. dp[b][1] = f[b][1];
  19. dp[b][0] = INF;
  20. }
  21. }

在无优化中 trans函数是编辑了vis数组

而在部分优化中 trans函数直接将对应的dp值设置为最大值-INF

这样在min中的挑选下,肯定能将设为INF的状态过滤掉

关于LCAans函数

  1. ll LCAans(int x,int y){
  2. int t;
  3. if(deep[x] < deep[y]) swap(x,y);//调换x为跟深的节点
  4. while (deep[x] > deep[y] && father[x] != y){//调节至同一深度&&x不为y
  5. t = father[x];
  6. dp[t][1] = f[t][1] - min(f[x][0],f[x][1]) + min(dp[x][0],dp[x][1]);
  7. dp[t][0] = f[t][0] - f[x][1] + dp[x][1];
  8. x = t;
  9. }
  10. if(father[x] == y){//若x为y的儿子
  11. dp[y][1] = dp[y][1] - min(f[x][0],f[x][1]) + min(dp[x][0],dp[x][1]);
  12. dp[y][0] = dp[y][0] - f[x][1] + dp[x][1];
  13. return min(dp[y][1] + ff[y][1],dp[y][0] + ff[y][0]);
  14. }
  15. while(father[x] != father[y]){//共同向上
  16. t = father[x];
  17. dp[t][1] = f[t][1] - min(f[x][0],f[x][1]) + min(dp[x][0],dp[x][1]);
  18. dp[t][0] = f[t][0] - f[x][1] + dp[x][1];
  19. x = t;
  20. t = father[y];
  21. dp[t][1] = f[t][1] - min(f[y][0],f[y][1]) + min(dp[y][0],dp[y][1]);
  22. dp[t][0] = f[t][0] - f[y][1] + dp[y][1];
  23. y = t;
  24. }
  25. t = father[x];//处理LCA节点时等于将两边都砍掉重新接
  26. dp[t][1] = f[t][1] - min(f[x][0],f[x][1]) + min(dp[x][0],dp[x][1])
  27. - min(f[y][0],f[y][1]) + min(dp[y][0],dp[y][1]);
  28. dp[t][0] = f[t][0] - f[x][1] + dp[x][1] - f[y][1] + dp[y][1];
  29. return min(dp[t][0] + ff[t][0],dp[t][1] + ff[t][1]);
  30. }

这是LCA非倍增的写法

遍历全代码 可以发现基本上都是重复的:

  1. t = father[x/y];
  2. dp[t][1] = f[t][1] - min(f[x/y][0],f[x/y][1]) + min(dp[x/y][0],dp[x/y][1]);
  3. dp[t][0] = f[t][0] - f[x/y][1] + dp[x/y][1];

理解性来看

就是把t节点的下半部分置换成更新好的下半部分

然后作为其dp值

tushi-3.jpg

还有一点要强调

就是若x为y的儿子那块

被砍腿的是dp数组而不是f数组

因为y也是有要求的

但是f[y]没有被INF给标记过

因此要用被标记过的dp来砍

main()函数中要注意的几点

  1. //只截取了for循环的部分
  2. trans(i);
  3. ll res = LCAans(rest[i].node1,rest[i].node2);
  4. if(res < INF) cout << res << endl;
  5. else cout << "-1" << endl;
  • 记得调用trans(i)

    • 每轮都要预处理
  • LCAans的代入值是node1,node2

    • 因为LCA从要修改的节点开展
  • 要加入res与INF的比较

    • 如果res>INF则说明无法同时满足两种情况

算法评估

通过两次Dfs求出了 \(f\)\(ff\) 数组

将上下两端的计算量大大减少

明显提升的算法效率

但是遇到中间部分比较长的情况

就需要用到大量的时间来反复处理

既然是LCA 那自然可以想到倍增的算法

接下来就进行倍增的处理

百分优化

解题方法

100分代码与68分代码大致相同

共有以下变化

  • father增加了对次方祖先的表达
  • 用两个一维小数组来代替dp数组
  • 添加了LCA函数

father数组

之前的father数组只用于表达节点的亲生父亲

而现在表达的是 u 的 \(2^t\) 辈祖先

因此dfs1中的father的表达也要有所改变:

  1. father[u][0] = fa;

\(2^0 = 1\) 即为 u 的亲生父亲

LCA函数

其主要作用是计算出fa数组 ———用于倍增是树段的计算

fa数组就是这个优化的核心部分

fa数组代表的含义为

u节点的 \(2^t\) 辈祖先为根的子树 减去 u节点为根的子树

所对应的最小权值

第一个0(不取)/1(取)对应u

第二个0(不取)/1(取)对应u的\(2^t\)辈祖先

tushi-3.png

这个fa数组是用递推求出的:

  1. void LCA(){
  2. for(int i = 1;i <= n;i++){
  3. int t = father[i][0];
  4. fa[i][0][0][0] = INF;
  5. fa[i][0][0][1] = f[t][1] - min(f[i][0],f[i][1]);
  6. fa[i][0][1][0] = f[t][0] - f[i][1];
  7. fa[i][0][1][1] = fa[i][0][0][1];
  8. }
  9. for(int t = 1;t <= 20;t++){
  10. for(int i = 1;i <= n;i++){
  11. int X = father[i][t-1];
  12. father[i][t] = father[X][t-1];
  13. fa[i][t][0][0] = min(fa[i][t-1][0][0] + fa[X][t-1][0][0],
  14. fa[i][t-1][0][1] + fa[X][t-1][1][0]);
  15. fa[i][t][0][1] = min(fa[i][t-1][0][0] + fa[X][t-1][0][1],
  16. fa[i][t-1][0][1] + fa[X][t-1][1][1]);
  17. fa[i][t][1][0] = min(fa[i][t-1][1][0] + fa[X][t-1][0][0],
  18. fa[i][t-1][1][1] + fa[X][t-1][1][0]);
  19. fa[i][t][1][1] = min(fa[i][t-1][1][0] + fa[X][t-1][0][1],
  20. fa[i][t-1][1][1] + fa[X][t-1][1][1]);
  21. }
  22. }
  23. }
第一个for循环

这是递推的基础

定义 t 为i的亲生父亲

fa[i][0][0][0]:

i和t都为0(不取) 不符合题意 因此取INF

fa[i][0][0][1]:

i不取t取 因为t是取的 所以f[i]是要取min的

fa[i][0][1][0]:

i取t不取 因为t是不取 所以f[i]只能为1

fa[i][0][1][1]:

i取t取 因为都是自由的 所以和 fa[i][0][0][1] 相同

第二个for循环

原理:

这里用了一个中将量 X

处理 X 的 0/1 状态

因为 fa 是已经处理好的最小权值

所以直接简单相加就可以了

可行性:

t 代表 i 的 \(2^t\) 辈祖先

由于循环外层是 t 内层为 i

说明 t - 1 层已经循环处理完毕了

因此用 X 这个中间量是可以的

father数组:

利用 X 这个中间值可递推出father

可行性与上文相同

LCAans函数

  1. ll LCAans(int x,int y,int val1,int val2){
  2. ll tx[2] = {0,0};
  3. ll ty[2] = {0,0};
  4. dpx[0] = dpx[1] = INF;
  5. dpy[0] = dpy[1] = INF;
  6. if(deep[x] < deep[y]){
  7. swap(x,y);
  8. swap(val1,val2);
  9. }
  10. dpx[val1] = f[x][val1];
  11. dpy[val2] = f[y][val2];

我们为了实现0/1的要求

我们先把 dpx 和 dpy 全部赋值成 INF

然后再将可通行的赋值为正常值

  1. for(int t = 20;t >= 0;t--){
  2. if((deep[x] - deep[y]) >= (1<<t)){
  3. tx[0] = min(fa[x][t][0][0] + dpx[0],
  4. fa[x][t][1][0] + dpx[1]);
  5. tx[1] = min(fa[x][t][0][1] + dpx[0],
  6. fa[x][t][1][1] + dpx[1]);
  7. dpx[0] = tx[0];
  8. dpx[1] = tx[1];
  9. x = father[x][t];
  10. }
  11. }
  12. if(x == y) return dpx[val2] + ff[x][val2];

这里将 x 和 y 移动到同一层

执行条件是 x 和 y 之间的距离大于 \(2^t\)

这保证了 x 不会跳过头

然后就是嫁接的部分了

这里的 tx 是 x 的 \(2^t\) 辈祖先

最后要判断 x 是否和 y 重合

因为如果重合了

y 是不能随意取的

需要满足 val2 的要求

  1. for(int t = 20;t >= 0;t--){
  2. if(father[x][t] != father[y][t]){
  3. tx[0] = min(fa[x][t][0][0] + dpx[0],
  4. fa[x][t][1][0] + dpx[1]);
  5. tx[1] = min(fa[x][t][0][1] + dpx[0],
  6. fa[x][t][1][1] + dpx[1]);
  7. dpx[0] = tx[0];
  8. dpx[1] = tx[1];
  9. x = father[x][t];
  10. ty[0] = min(fa[y][t][0][0] + dpy[0],
  11. fa[y][t][1][0] + dpy[1]);
  12. ty[1] = min(fa[y][t][0][1] + dpy[0],
  13. fa[y][t][1][1] + dpy[1]);
  14. dpy[0] = ty[0];
  15. dpy[1] = ty[1];
  16. y = father[y][t];
  17. }
  18. }

执行条件是他们的 \(2^t\) 辈祖先不是同一个

这让循环结束后 x 和 y 在他们的 LCA 下方

这里的嫁接和上文同理 不再赘叙

  1. int t = father[x][0];
  2. ll lca_0 = f[t][0] - f[x][1] - f[y][1] + dpx[1] + dpy[1] + ff[t][0];
  3. ll lca_1 = f[t][1] - min(f[x][0],f[x][1]) - min(f[y][0],f[y][1])
  4. + min(dpx[0],dpx[1]) + min(dpy[0],dpy[1]) + ff[t][1];
  5. return min(lca_0,lca_1);
  6. }

这里是处理返回值 和上文相同

代码

44分

  1. //P5024 44p 注释版
  2. #include<bits/stdc++.h>
  3. #define ll long long
  4. #define maxn 100005
  5. using namespace std;
  6. int n,m,val[maxn],vis[maxn];
  7. char type[100];
  8. ll f[maxn][2];
  9. /*
  10. n 城市数量(即节点数) m 要求数量
  11. val[i] 城市i所部署军队的耗资(即节点i的权值)
  12. vis[i] 要求的存储变量 vis[i] = 0(代表城市i不得驻军 即节点i不可取) 1(代表城市i必须驻军 即节点i必取)
  13. type[] 用来存储规模参数
  14. f[i][j] i代表节点 j = 0(代表不取当前节点的最小子树权值和) 1(代表取当前节点的最小子树权值和)
  15. */
  16. int cnt,head[maxn];
  17. struct tree{
  18. int u,v;
  19. tree(int a = 0,int b = 0){
  20. v = a;
  21. u = head[b];
  22. }
  23. }e[maxn<<1];
  24. //邻接表存图
  25. struct Rest{
  26. int node1,node2;
  27. int val1,val2;
  28. }rest[maxn];/*
  29. 用结构体来存储要求
  30. node1/2存要求的节点
  31. val1/2存必取或必不取
  32. */
  33. void Read(){//读入
  34. int a,b;
  35. cin >> n >> m >> type;
  36. for(int i = 1;i <= n;i++) cin >> val[i]; //存节点权值
  37. for(int i = 1;i < n;i++){//存图
  38. cin >> a >> b;
  39. e[++cnt] = tree(a,b);
  40. head[b] = cnt;
  41. e[++cnt] = tree(b,a);
  42. head[a] = cnt;
  43. }
  44. int x,y;
  45. for(ll i = 1;i <= m;i++){//读入要求
  46. cin >> a >> x >> b >> y;
  47. rest[i].node1 = a;
  48. rest[i].val1 = x;
  49. rest[i].node2 = b;
  50. rest[i].val2 = y;
  51. }
  52. }
  53. void trans(int id){//在dfs前调用 预处理要求
  54. memset(vis,2,sizeof(vis));
  55. vis[rest[id].node1] = rest[id].val1;
  56. vis[rest[id].node2] = rest[id].val2;
  57. }
  58. ll dfs(int u,int fa){//深搜 树形dp
  59. if((vis[u]==0)&&(vis[fa]==0)) return -1;
  60. //排除不可能的情况 即父节点和子节点都取不得 不符合题意
  61. f[u][0] = 0;//父节点不选的时候
  62. f[u][1] = val[u];//父节点选的时候
  63. for(int i = head[u];i;i = e[i].u){//搜每一个父向子的边
  64. int ev = e[i].v;//ev 即子节点
  65. if(ev == fa) continue;//防止向上爬
  66. if(dfs(ev,u) < 0) return -1;//继续往下搜 如果不满足题意则直接返回-1
  67. f[u][0] += f[ev][1];/*
  68. 当父节点不选的时候
  69. 子节点都必须选择
  70. 所以直接累加子节点选择时的权值
  71. */
  72. if(vis[ev] == 0){
  73. //子节点不能选 则父节点必须选
  74. f[u][1] += f[ev][0];
  75. vis[u] = 1;//修改父节点为必选
  76. } else if (vis[ev] == 1) {
  77. //子节点必选 则只累加子节点必选的最小子树值
  78. f[u][1] += f[ev][1];
  79. } else {
  80. //没有限制 则择优选择小的上报
  81. f[u][1] = min(f[u][1] + f[ev][1],f[u][1] + f[ev][0]);
  82. }/*
  83. 当父节点选的时候
  84. 子节点可以选或不选
  85. */
  86. }
  87. if(vis[u] == 1) return f[u][1];
  88. if(vis[u] == 0) return f[u][0];
  89. return min(f[u][1],f[u][0]);/*
  90. 通过条件决定返回值
  91. 用于输出结果
  92. */
  93. }
  94. int main(){
  95. Read();//读入
  96. for(int i = 1;i <= m;i++){//循环每个条件
  97. trans(i);//读入条件 预处理
  98. ll ans = dfs(1,0);//深搜求答案
  99. cout << ans <<endl;//输出
  100. }
  101. return 0;
  102. }

68分

  1. #include<bits/stdc++.h>
  2. #define ll long long
  3. #define maxn 100005
  4. #define INF 1e12
  5. using namespace std;
  6. int n,m;
  7. int head[maxn],cnt;
  8. int val[maxn],deep[maxn],father[maxn];
  9. char type[100];
  10. ll f[maxn][2],ff[maxn][2],dp[maxn][2];
  11. struct Edge{
  12. int u,v;
  13. Edge(int a = 0,int b = 0){
  14. u = head[a];
  15. v = b;
  16. }
  17. }e[maxn<<1];
  18. struct Rest{
  19. int node1,node2;
  20. int val1,val2;
  21. }rest[maxn];
  22. void Read(){
  23. int a,b;
  24. cin >> n >> m >> type;
  25. for(int i = 1;i <= n;i++){
  26. cin >> val[i];
  27. }
  28. for(int i = 1;i <= (n-1);i++){
  29. cin >> a >> b;
  30. e[++cnt] = Edge(a,b);
  31. head[a] = cnt;
  32. e[++cnt] = Edge(b,a);
  33. head[b] = cnt;
  34. }
  35. for(int i = 1;i <= m;i++){
  36. cin >> rest[i].node1 >> rest[i].val1;
  37. cin >> rest[i].node2 >> rest[i].val2;
  38. }
  39. }
  40. void dfs1(int u,int fa){
  41. f[u][0] = 0;
  42. f[u][1] = val[u];
  43. father[u] = fa;
  44. deep[u] = deep[fa] + 1;
  45. for(int i = head[u];i;i = e[i].u){
  46. int ev = e[i].v;
  47. if(ev == fa) continue;
  48. dfs1(ev,u);
  49. f[u][0] += f[ev][1];
  50. f[u][1] += min(f[ev][0],f[ev][1]);
  51. }
  52. }
  53. void dfs2(int u,int fa){
  54. for(int i = head[u];i;i = e[i].u){
  55. int ev = e[i].v;
  56. if(ev == fa) continue;
  57. ff[ev][0] = ff[u][1] + f[u][1] - min(f[ev][0],f[ev][1]);
  58. ff[ev][1] = min(ff[u][0] + f[u][0] - f[ev][1],ff[ev][0]);
  59. dfs2(ev,u);
  60. }
  61. }
  62. void trans(int id){
  63. int a = rest[id].node1;
  64. int b = rest[id].node2;
  65. int x = rest[id].val1;
  66. int y = rest[id].val2;
  67. memset(dp,sizeof(dp),0);
  68. if(x == 0){
  69. dp[a][0] = f[a][0];
  70. dp[a][1] = INF;
  71. } else {
  72. dp[a][1] = f[a][1];
  73. dp[a][0] = INF;
  74. }
  75. if(y == 0){
  76. dp[b][0] = f[b][0];
  77. dp[b][1] = INF;
  78. } else {
  79. dp[b][1] = f[b][1];
  80. dp[b][0] = INF;
  81. }
  82. }
  83. ll LCAans(int x,int y){
  84. int t;
  85. if(deep[x] < deep[y]) swap(x,y);
  86. while (deep[x] > deep[y] && father[x] != y){
  87. t = father[x];
  88. dp[t][1] = f[t][1] - min(f[x][0],f[x][1]) + min(dp[x][0],dp[x][1]);
  89. dp[t][0] = f[t][0] - f[x][1] + dp[x][1];
  90. x = t;
  91. }
  92. if(father[x] == y){
  93. dp[y][1] = dp[y][1] - min(f[x][0],f[x][1]) + min(dp[x][0],dp[x][1]);
  94. dp[y][0] = dp[y][0] - f[x][1] + dp[x][1];
  95. return min(dp[y][1] + ff[y][1],dp[y][0] + ff[y][0]);
  96. }
  97. while(father[x] != father[y]){
  98. t = father[x];
  99. dp[t][1] = f[t][1] - min(f[x][0],f[x][1]) + min(dp[x][0],dp[x][1]);
  100. dp[t][0] = f[t][0] - f[x][1] + dp[x][1];
  101. x = t;
  102. t = father[y];
  103. dp[t][1] = f[t][1] - min(f[y][0],f[y][1]) + min(dp[y][0],dp[y][1]);
  104. dp[t][0] = f[t][0] - f[y][1] + dp[y][1];
  105. y = t;
  106. }
  107. t = father[x];
  108. dp[t][1] = f[t][1] - min(f[x][0],f[x][1]) + min(dp[x][0],dp[x][1])
  109. - min(f[y][0],f[y][1]) + min(dp[y][0],dp[y][1]);
  110. dp[t][0] = f[t][0] - f[x][1] + dp[x][1] - f[y][1] + dp[y][1];
  111. return min(dp[t][0] + ff[t][0],dp[t][1] + ff[t][1]);
  112. }
  113. int main(){
  114. Read();
  115. dfs1(1,0);
  116. dfs2(1,0);
  117. for(int i = 1;i <= m;i++){
  118. trans(i);
  119. ll res = LCAans(rest[i].node1,rest[i].node2);
  120. if(res < INF) cout << res << endl;
  121. else cout << "-1" << endl;
  122. }
  123. return 0;
  124. }

100分

  1. #include<bits/stdc++.h>
  2. #define ll long long
  3. #define maxn 100005
  4. #define INF 1e12
  5. using namespace std;
  6. int n,m,val[maxn];
  7. int head[maxn],cnt;
  8. int deep[maxn],father[maxn][25];
  9. char type[100];
  10. ll dpx[2],dpy[2];
  11. ll f[maxn][2],ff[maxn][2];
  12. ll fa[maxn][25][2][2];
  13. struct Edge{
  14. int u,v;
  15. Edge(int a = 0,int b = 0){
  16. u = head[a];
  17. v = b;
  18. }
  19. }e[maxn<<1];
  20. struct Rest{
  21. int node1,node2;
  22. int val1,val2;
  23. }rest[maxn];
  24. void Read(){
  25. int a,b;
  26. cin >> n >> m >> type;
  27. for(int i = 1;i <= n;i++) cin >> val[i];
  28. for(int i = 1;i < n;i++){
  29. cin >> a >> b;
  30. e[++cnt] = Edge(a,b);
  31. head[a] = cnt;
  32. e[++cnt] = Edge(b,a);
  33. head[b] = cnt;
  34. }
  35. for(int i = 1;i <= m;i++){
  36. cin >> rest[i].node1 >> rest[i].val1;
  37. cin >> rest[i].node2 >> rest[i].val2;
  38. }
  39. }
  40. void dfs1(int u,int fa){
  41. f[u][0] = 0;
  42. f[u][1] = val[u];
  43. father[u][0] = fa;
  44. deep[u] = deep[fa] + 1;
  45. for(int i = head[u];i;i = e[i].u){
  46. int ev = e[i].v;
  47. if(ev == fa) continue;
  48. dfs1(ev,u);
  49. f[u][0] += f[ev][1];
  50. f[u][1] += min(f[ev][1],f[ev][0]);
  51. }
  52. }
  53. void dfs2(int u,int fa){
  54. for(int i = head[u];i;i = e[i].u){
  55. int ev = e[i].v;
  56. if(ev == fa) continue;
  57. ff[ev][0] = ff[u][1] + f[u][1] - min(f[ev][0],f[ev][1]);
  58. ff[ev][1] = min(ff[u][0] + f[u][0] - f[ev][1],ff[ev][0]);
  59. dfs2(ev,u);
  60. }
  61. }
  62. void LCA(){
  63. for(int i = 1;i <= n;i++){
  64. int t = father[i][0];
  65. fa[i][0][0][0] = INF;
  66. fa[i][0][0][1] = f[t][1] - min(f[i][0],f[i][1]);
  67. fa[i][0][1][0] = f[t][0] - f[i][1];
  68. fa[i][0][1][1] = fa[i][0][0][1];
  69. }
  70. for(int t = 1;t <= 20;t++){
  71. for(int i = 1;i <= n;i++){
  72. int X = father[i][t-1];
  73. father[i][t] = father[X][t-1];
  74. fa[i][t][0][0] = min(fa[i][t-1][0][0] + fa[X][t-1][0][0],
  75. fa[i][t-1][0][1] + fa[X][t-1][1][0]);
  76. fa[i][t][0][1] = min(fa[i][t-1][0][0] + fa[X][t-1][0][1],
  77. fa[i][t-1][0][1] + fa[X][t-1][1][1]);
  78. fa[i][t][1][0] = min(fa[i][t-1][1][0] + fa[X][t-1][0][0],
  79. fa[i][t-1][1][1] + fa[X][t-1][1][0]);
  80. fa[i][t][1][1] = min(fa[i][t-1][1][0] + fa[X][t-1][0][1],
  81. fa[i][t-1][1][1] + fa[X][t-1][1][1]);
  82. }
  83. }
  84. }
  85. ll LCAans(int x,int y,int val1,int val2){
  86. ll tx[2] = {0,0};
  87. ll ty[2] = {0,0};
  88. dpx[0] = dpx[1] = INF;
  89. dpy[0] = dpy[1] = INF;
  90. if(deep[x] < deep[y]){
  91. swap(x,y);
  92. swap(val1,val2);
  93. }
  94. dpx[val1] = f[x][val1];
  95. dpy[val2] = f[y][val2];
  96. for(int t = 20;t >= 0;t--){
  97. if((deep[x] - deep[y]) >= (1<<t)){
  98. tx[0] = min(fa[x][t][0][0] + dpx[0],
  99. fa[x][t][1][0] + dpx[1]);
  100. tx[1] = min(fa[x][t][0][1] + dpx[0],
  101. fa[x][t][1][1] + dpx[1]);
  102. dpx[0] = tx[0];
  103. dpx[1] = tx[1];
  104. x = father[x][t];
  105. }
  106. }
  107. if(x == y) return dpx[val2] + ff[x][val2];
  108. for(int t = 20;t >= 0;t--){
  109. if(father[x][t] != father[y][t]){
  110. tx[0] = min(fa[x][t][0][0] + dpx[0],
  111. fa[x][t][1][0] + dpx[1]);
  112. tx[1] = min(fa[x][t][0][1] + dpx[0],
  113. fa[x][t][1][1] + dpx[1]);
  114. dpx[0] = tx[0];
  115. dpx[1] = tx[1];
  116. x = father[x][t];
  117. ty[0] = min(fa[y][t][0][0] + dpy[0],
  118. fa[y][t][1][0] + dpy[1]);
  119. ty[1] = min(fa[y][t][0][1] + dpy[0],
  120. fa[y][t][1][1] + dpy[1]);
  121. dpy[0] = ty[0];
  122. dpy[1] = ty[1];
  123. y = father[y][t];
  124. }
  125. }
  126. int t = father[x][0];
  127. ll lca_0 = f[t][0] - f[x][1] - f[y][1] + dpx[1] + dpy[1] + ff[t][0];
  128. ll lca_1 = f[t][1] - min(f[x][0],f[x][1]) - min(f[y][0],f[y][1])
  129. + min(dpx[0],dpx[1]) + min(dpy[0],dpy[1]) + ff[t][1];
  130. return min(lca_0,lca_1);
  131. }
  132. int main(){
  133. Read();
  134. dfs1(1,0);
  135. dfs2(1,0);
  136. LCA();
  137. for(int i = 1;i <= m;i++){
  138. ll res = LCAans(rest[i].node1,rest[i].node2,rest[i].val1,rest[i].val2);
  139. if(res < INF) cout << res << endl;
  140. else cout << "-1" <<endl;
  141. }
  142. return 0;
  143. }

原文链接:http://www.cnblogs.com/rosyr050301/p/Defendthekingdom.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号