51nod 2621 树上距离 (倍增+ LCA 模板)
有一棵n个节点的无向树,每条边有一个边权,现在有q次询问,每次询问给出两个点,求这两个点之间的简单路径上的边权和是多少。
输入格式
第1行:两个整数n和q,n表示这棵树的节点个数,q表示查询的次数。(1<=n,q<=100000) 第2行~第n行:每行有三个整数u,v,w,表示u与v之间有一条权值为w的边。(1<=w<=100000) 第n+1行~n+q行:每行有两个正整数x,y,表示要查询的两个点的编号。
输出格式
第1行-第q行:每行输出一个数,表示那要查询的两点之间的简单路径上的边权和。
输入样例
4 2
2 1 2
4 3 2
1 4 3
1 2
3 2
输出样例
2
7
样例解释
如图所示的数据中:
1号节点和2号节点之间的距离为:2
2号节点和3号节点之间的距离为:2+2+3=7
AC代码:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<vector>
#include<set>
#include<map>
#include<cstring>
#define ll long long
using namespace std;
const int N = 1e5 +10;
int n, q;
int f[N][30], dep[N];
ll dis[N];
struct Edge{
int to, cost;
};
vector<Edge> g[N];
void dfs(int u, int fa){
f[u][0] = fa; //
for (int i = 1; i <= 20; i++)
f[u][i] = f[f[u][i-1]][i-1];
for(int i = 0; i < g[u].size(); i++){
Edge e = g[u][i];
if(e.to != fa){
dis[e.to] = dis[u] + e.cost;
dep[e.to] = dep[u] + 1;
dfs(e.to, u);
}
}
}
void init(){
int u, v, w;
for(int i = 1; i <= n - 1; i++){
cin >> u >> v >> w;
g[u].push_back(Edge{v, w});
g[v].push_back(Edge{u, w});
}
dis[1] = 0;
dep[1] = 0;
dfs(1, 0);
}
int lca (int u , int v){
if(dep[u] < dep[v]) swap(u, v);
int k = dep[u] - dep[v];
for(int i = 20; i >= 0 ; i--){
if((k >> i) & 1)
u = f[u][i];
}
if(u == v) return u;
for(int i = 20; i >= 0; i--){
if(f[u][i] != f[v][i]){
u = f[u][i];
v = f[v][i];
}
}
return f[u][0];
}
int main(){
cin >> n >> q;
init();
int u, v;
while(q--){
cin >> u >> v;
cout << dis[u] + dis[v] - 2 * dis[lca(u, v)] << endl;
}
}