📅  最后修改于: 2023-12-03 15:06:48.350000             🧑  作者: Mango
LCA (Lowest Common Ancestor) 问题在树的查询中经常被遇到。其中一种变形是通过 LCA 查询两个节点之间的最大和最小权重。
树是由节点和各节点之间的边组成的一种数据结构。每个节点包含一个权重(可以为空),每个边连接两个节点。
LCA 是指在树中,两个节点最近的共同祖先节点。
给定一棵有根树和两个节点,需要在这个树中查询它们之间的最大和最小权重。
为了解决此问题,我们可以使用 LCA。首先,我们需要对树进行预处理以构建一个父亲数组和一个深度数组。
父亲数组是一个包含每个节点的父节点的数组。它的构建可以通过深度优先遍历(DFS)树来实现。
int parent[N]; // N 表示节点数量
vector<int> adj[N]; // 存储节点的边
void dfs(int node, int father) {
parent[node] = father;
for (int i = 0; i < adj[node].size(); i++) {
int child = adj[node][i];
if (child != father) {
dfs(child, node);
}
}
}
深度数组包含每个节点的深度。它可以通过深度优先遍历树来实现。在遍历时,我们可以通过记录每个节点的深度来计算其子节点的深度。
int depth[N]; // N 表示节点数量
void dfs(int node, int father, int d) {
depth[node] = d;
for (int i = 0; i < adj[node].size(); i++) {
int child = adj[node][i];
if (child != father) {
dfs(child, node, d + 1);
}
}
}
有了上述预处理,接下来我们就可以计算 LCA,并通过 LCA 计算最大和最小权重了。
按照 LCA 的定义,我们可以通过向上跳两个节点的深度差来找到它们的 LCA。如果一个节点的深度大于另一个节点,那么我们就向上跳它们的深度差,直到找到一个节点的深度等于另一个节点的深度。然后,我们就可以继续向上跳,直到找到它们共同的祖先。
int lca(int x, int y) {
while (depth[x] > depth[y]) x = parent[x];
while (depth[x] < depth[y]) y = parent[y];
while (x != y) {
x = parent[x];
y = parent[y];
}
return x;
}
有了 LCA,我们就可以轻松地计算最大和最小权重。对于一个节点的权重,我们可以在和它的 LCA 之间找到所有节点的最大和最小权重。为了实现这一点,我们可以在向上跳查找 LCA 时记录最大值和最小值。
int mx = 0, mn = INF;
void update(int node, int lca) {
while (depth[node] > depth[lca]) {
mx = max(mx, weight[node]);
mn = min(mn, weight[node]);
node = parent[node];
}
}
void calc(int x, int y) {
int ancestor = lca(x, y);
mx = 0, mn = INF;
update(x, ancestor);
update(y, ancestor);
printf("Max weight: %d\n", mx);
printf("Min weight: %d\n", mn);
}
通过预处理父亲数组和深度数组,我们可以计算 LCA,并利用 LCA 计算任意两个节点的最大和最小权重。