3.3节后习题
题目要求
一、基础题
1. 给定一棵完全二叉树,根为 1 号结点,求以下结点对的 LCA 和距离:
(7, 8) (5, 9) (3, 6)
2. 证明:在完全二叉树中,结点 i 的父结点为 ⌊i/2⌋。
二、进阶题
1. 实现倍增法求解 LCA,以下哪个是倍增法的核心思想?
2. 扩展代码支持计算树上任意两点距离,如何计算点u和点v的距离?
三、拓展题
1. 动态树场景下,若允许树的边权动态修改,下列哪种数据结构最适合优化距离计算?
2. 多结点LCA:计算三个结点u、v、w的LCA,最优算法是什么?
参考代码
以下是倍增法求解LCA以及计算树上距离的参考代码:
代码
cpp
#include <iostream>
#include <vector>
using namespace std;
const int MAXN = 5e5 + 5;
const int LOG = 20;
vector<int> adj[MAXN];
int depth[MAXN];
int fa[MAXN][LOG];
void dfs(int u, int parent) {
depth[u] = depth[parent] + 1;
fa[u][0] = parent;
for (int k = 1; k < LOG; k++)
fa[u][k] = fa[fa[u][k-1]][k-1];
for (int v : adj[u]) {
if (v != parent)
dfs(v, u);
}
}
int lca(int u, int v) {
if (depth[u] < depth[v]) swap(u, v);
for (int k = LOG - 1; k >= 0; k--) {
if (depth[u] - (1 << k) >= depth[v])
u = fa[u][k];
}
if (u == v) return u;
for (int k = LOG - 1; k >= 0; k--) {
if (fa[u][k] != fa[v][k]) {
u = fa[u][k];
v = fa[v][k];
}
}
return fa[u][0];
}
int get_distance(int u, int v) {
int l = lca(u, v);
return depth[u] + depth[v] - 2 * depth[l];
}
int main() {
int n, m, s;
cin >> n >> m >> s;
for (int i = 0; i < n - 1; i++) {
int x, y;
cin >> x >> y;
adj[x].push_back(y);
adj[y].push_back(x);
}
depth[0] = -1;
dfs(s, 0);
while (m--) {
int u, v;
cin >> u >> v;
cout << lca(u, v) << endl; // 求LCA
// cout << get_distance(u, v) << endl; // 求距离
}
return 0;
}