51nod 2621 树上距离 (倍增+ LCA 模板)

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;
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值