V

算法可视化

ZHEN
分享到微博分享到 XGitHub 仓库个人主页
学习工具算法复杂度速查算法学习路径
数据结构数组链表栈队列树堆哈希表图字典树并查集LRU 缓存跳表线段树B+ 树布隆过滤器树状数组
经典排序算法冒泡排序鸡尾酒排序双调排序选择排序插入排序二分插入排序希尔排序归并排序自顶向下归并快速排序三路快排双轴快排堆排序计数排序基数排序桶排序
图算法Dijkstra 最短路Kruskal 最小生成树Prim 最小生成树Bellman-Ford 最短路拓扑排序Floyd 多源最短路强连通分量2-SAT最大流二分图匹配LCA 倍增欧拉路径
动态规划编辑距离0-1 背包完全背包最长公共子序列最长递增子序列硬币找零方案数石子合并旅行商 TSP树形 DP数位 DP换根 DP
回溯与搜索N 皇后子集生成全排列组合总和迷宫寻路岛屿数量单词搜索数独A* 寻路
字符串KMP 字符串匹配Rabin-KarpBoyer-MooreManacher后缀数组LCP / height 数组AC 自动机Z 函数
数学与数论埃氏筛线性筛欧几里得算法快速幂扩展欧几里得中国剩余定理欧拉函数米勒-拉宾FFTPollard's Rho
计算几何凸包旋转卡壳最近点对线段相交扫描线求交
查找二分查找二分边界旋转数组搜索二分答案三分查找

换根 DP(树中距离之和)

动态规划 · 二次扫描 · 每个点都当一次根

每个点都要答案

求树上每个节点到其余所有点的距离之和。树形 DP 固定一个根算一次没问题,可这里 n 个点都要——逐点重跑就是 O(n²)。本页的树:

      0          ← 先当根
     / \
    1   2
   / \
  3   4

换根:账本不用重记,挪一格改两笔

第一趟(后序):老老实实算出每个点的 size(子树大小)和 down(到子树内所有点的距离和),顺手得到根的答案 ans[0] = down[0]。第二趟(前序):根从 u 挪到相邻的 v——v 子树里 size[v] 个点近了 1 步、其余 n − size[v] 个点远了 1 步:ans[v] = ans[u] − size[v] + (n − size[v])。一步 O(1),全树 O(n)。下表三列逐格点亮,黄格是每一步引用的账本。右侧代码随每一步同步高亮。

sizedownans
0·根
1·L
2·R
3·LL
4·LR

求「树上所有点到 u 的距离和」——每个 u 都要!逐点 BFS 是 O(n²)。换根 DP 二次扫描:第一趟后序算「子树内」(size 与 down),第二趟前序把答案从父亲推给孩子,全树 O(n)

1function sumOfDistances(n: number, adj: number[][]): number[] {
2 const size = new Array(n).fill(1);
3 const down = new Array(n).fill(0);
4 const ans = new Array(n).fill(0);
5 const dfs1 = (u: number, p: number): void => { // 第一趟:后序
6 for (const v of adj[u]) if (v !== p) {
7 dfs1(v, u);
8 size[u] += size[v];
9 down[u] += down[v] + size[v]; // 孩子子树整体抬 1 步
10 }
11 };
12 const dfs2 = (u: number, p: number): void => { // 第二趟:前序换根
13 for (const v of adj[u]) if (v !== p) {
14 ans[v] = ans[u] - size[v] + (n - size[v]); // 近 size[v] 远 n−size[v]
15 dfs2(v, u);
16 }
17 };
18 dfs1(0, -1);
19 ans[0] = down[0]; // 第一趟收官:根的答案
20 dfs2(0, -1);
21 return ans;
22}
树0 根;1,2 为子;3,4 为 1 的子
目标ans[u] = Σ dist(u, ·),全部 5 个
1 / 12

换根三件套

①第一趟后序:把「子树内」的信息算干净(size / down / 子树最远……)。
②可增量修正:答案对「根挪一步」能 O(1) 修正——距离和的近远账、最值的换根合并。
③第二趟前序:沿树把修正传下去,每点各得其所。
坑:第二趟必须用父亲已换根后的答案推孩子(前序),别用第一趟的旧值。

同款还有:树的中心(最远距离最小的点)、每点的最远节点(向上/向下两条最长路合并)、834 距离之和原题。至此 DP 大类十一页真收官:序列、区间、集合、树、数位五种状态设计,外加「一趟不够就两趟」的换根——动态规划的常用武器全部上墙。