276 字
1 分钟
竞赛算法(6) 树上问题
2025-11-26
无标签

树的dfs#

完美, 简洁, 易于理解. 以维护子树大小为例:

int siz[N];
vector<int> adj[N]; // 邻接表存无向边
auto dfs = [&](auto&& self, int x, int p) {
siz[x] = 1;
for (const auto& y : adj[x]) {
if (y == p) continue;
self(self, y, x);
siz[x] += siz[y];
}
};
// 调用
dfs(dfs, root, -1);

LCA#

倍增算法#

O(NlogN)O(N\log N)的时间内预处理, 在O(logN)O(\log N)时间内查询.

constexpr int N = 2e5 + 50;
constexpr int LOG = 20; // 2^18 约 26 万
int up[N][LOG + 1];
int depth[N];
vector<int> adj[N];
// 预处理depth数组和up数组
void dfs(int x, int p) {
for (int i = 1; i <= LOG; i++) {
up[x][i] = up[up[x][i - 1]][i - 1];
}
for (const auto& y : adj[x]) {
if (y == p) continue;
depth[y] = depth[x] + 1;
up[y][0] = x;
dfs(y, x);
}
}
// 求lca
int getlca(int x, int y) {
if (depth[x] < depth[y]) swap(x, y);
for (int i = LOG; i >= 0; i--) {
if (depth[x] - (1 << i) >= depth[y]) {
x = up[x][i];
}
}
if (x == y) {
return x;
}
for (int i = LOG; i >= 0; i--) {
if (up[x][i] != up[y][i]) {
x = up[x][i];
y = up[y][i];
}
}
return up[x][0];
}

基于LCA求树上两点距离#

int dist(int x, int y) {
return depth[x] + depth[y] - 2 * depth[getlca(x, y)];
}
竞赛算法(6) 树上问题
https://fuwari.vercel.app/posts/竞赛算法6-树上问题/
作者
ykindred
发布于
2025-11-26
许可协议
CC BY-NC-SA 4.0