#lCAybttg040405. 1556:Dis
1556:Dis
题目描述
给出 个点的一棵树,多次询问两点之间的最短距离。
注意:边是双向的。
输入格式
第一行为两个整数 和 。 表示点数, 表示询问次数;
接下来 行,每行三个整数 ,表示点 和点 之间存在一条边长度为 ;
再接下来 行,每行两个整数 ,表示询问点 到点 的最短距离。
输出格式
输出 行。对于每次询问,输出一行结果。
样例
输入样例 1
2 2
1 2 100
1 2
2 1
输出样例 1
100
100
样例解释 1
树只有一条边,连接 和 ,长度为 ,所以任意询问两点距离都是 。
输入样例 2
3 2
1 2 10
3 1 15
1 2
3 2
输出样例 2
10
25
样例解释 2
树的结构:
1
/ \
10 15
/ \
2 3
- 询问 到 :距离 。
- 询问 到 :路径 ,距离 。
数据范围
时间限制:1000 ms
内存限制:524288 KB
提示
这是一个标准的树上两点距离查询问题。
对于树上任意两点 ,设它们的最近公共祖先为 ,则距离公式为:
$$dist(u, v) = depth[u] + depth[v] - 2 \times depth[lca(u, v)]$$其中 表示节点 到根节点的距离(即路径上所有边权之和),而不是深度(边数)。
另一种更直接的方法:预处理每个节点到根节点的距离 ,那么:
$$dist(u, v) = dis[u] + dis[v] - 2 \times dis[lca(u, v)]$$这个公式成立是因为 和 都包含从根到 的路径,减去两倍的 就得到 到 的路径长度。
实现步骤:
- 任选一个节点作为根(比如节点 ),DFS 预处理:
- 每个节点的深度(用于 LCA 跳跃);
- 每个节点到根的距离 ;
- 倍增数组 表示 的 级祖先。
- 对于每个询问 :
- 用倍增法求出 ;
- 输出 。
时间复杂度:预处理 ,每次询问 ,总复杂度 ,对于 完全足够。
也可以使用 Tarjan 离线算法 ,但倍增法更易于实现。