📅  最后修改于: 2023-12-03 14:58:36.459000             🧑  作者: Mango
这是门|门 IT 2008比赛中的第52题,考察了程序员对于算法和数据结构的理解和使用。
给定一棵有根树以及树中的一些点。对于每个点,求出其到根节点路径上(包括自身)各个点之间的距离。
第1行2个整数,N和M,表示树的节点数量和指定的点的数量。
接下来N-1行,每行2个整数u和v,表示一条边(u,v)。
接下来M行,每行一个整数p,表示指定的点的编号。
共M行,每行N个数,其中第i个数表示第i个指定点到根节点路径上第j个点(包括自身)的距离,每个数占一行。
题目中要求计算树上两点间距离,我们可以考虑使用树的LCA算法来实现,具体实现方式如下:
#include <iostream>
#include <vector>
using namespace std;
const int N = 100010;
int n, m;
int depth[N], fa[N][20]; //每个节点深度和所在的2^k个祖先节点
vector<int> g[N];
void dfs(int u, int father) //预处理深度和2^k祖先节点
{
depth[u] = depth[father] + 1;
fa[u][0] = father;
for (int i = 1; i <= 19; i++)
fa[u][i] = fa[fa[u][i - 1]][i - 1];
for (int v : g[u])
if (v != father)
dfs(v, u);
}
int lca(int a, int b) //计算两点距离
{
if (depth[a] < depth[b])
swap(a, b);
for (int i = 19; i >= 0; i--)
if (depth[fa[a][i]] >= depth[b])
a = fa[a][i];
if (a == b)
return a;
for (int i = 19; i >= 0; i--)
if (fa[a][i] != fa[b][i])
a = fa[a][i], b = fa[b][i];
return fa[a][0];
}
int main()
{
cin >> n >> m;
for (int i = 0; i < n - 1; i++)
{
int a, b;
cin >> a >> b;
g[a].push_back(b);
g[b].push_back(a);
}
dfs(1, 0);
while (m--)
{
int p;
cin >> p;
for (int i = 1; i <= n; i++)
cout << depth[i] - depth[lca(i, p)] << endl;
}
return 0;
}
本题使用树的LCA算法进行求解,时间复杂度为$O(n\log_2n)$,其中$n$为树的节点数量。
[1] 《算法竞赛进阶指南》第三章 树与图的深入应用
[2] ACWING官方题解