题意:
给出一个树,有n个结点,n-1条边。给出边的权值。求两个结点的路径上权值之和,保证只有一条路径。并且不能经过一个点两次。
思路:
倍增求LCA,模板题。讲解倍增求LCA的博客 先dfs,然后LCA。dfs的时候需要更新dis数组。
#pragma warning(disable:4996)
#include<iostream>
#include<cstdio>
#include<vector>
#include<queue>
#include<cmath>
#include<cstring>
#include<map>
#include<string>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N = 100005;
const ll inf = 4e18;
const ll mod = 1e9 + 7;
int head[N], fa[N][30], dep[N], dis[N];
//dep是结点的深度,dis是到根的距离。
struct node
{
int to, Next, dist;
//dist是边的权值
};
node e[N * 2];
int cnt;
void add(int u, int v, int w)
{
e[++cnt].to = v;
e[cnt].Next = head[u];
e[cnt].dist = w;
head[u] = cnt;
}
void dfs(int u, int f)
{
int i;
dep[u] = dep[f] + 1;
fa[u][0] = f;
//更新dep和fa[u][0]
for (i = 1; (1 << i) <= dep[u]; i++)
{
fa[u][i] = fa[fa[u][i - 1]][i - 1];
//fa[u][i]的值
}
for (i = head[u]; i; i = e[i].Next)
{
if (e[i].to != f)
{
dis[e[i].to] = dis[u] + e[i].dist;//计算dis
dfs(e[i].to, u);//dfs遍历下一个
}
}
}
int LCA(int a, int b)
{
int i;
if (dep[a] < dep[b])swap(a, b);
int d = dep[a] - dep[b];//差值
for (i = 0; (1 << i) <= d; i++)
{
if ((1 << i)&d)a = fa[a][i];
//使得a和b的深度相同
}
if (a == b)return a;
for (i = log2(dep[a]); i>=0; i--)
{
if (fa[a][i] != fa[b][i])//找到相同的父亲结点
{
a = fa[a][i];
b = fa[b][i];
}
}
return fa[a][0];
}
int main()
{
int T, n, m, i, j;
int x, y, z, a, b, ans, temp;
cin >> T;
while (T--)
{
cnt = 0;
memset(fa, 0, sizeof(fa));
memset(dep, 0, sizeof(dep));
memset(head, 0, sizeof(head));
memset(dis, 0, sizeof(dis));
cin >> n >> m;
for (i = 1; i < n; i++)
{
scanf("%d%d%d", &x, &y, &z);
add(x, y, z); add(y, x, z);
}
dfs(1, 0);
while (m--)
{
scanf("%d%d", &a, &b);
temp = LCA(a, b);
ans = dis[a] + dis[b] - 2 * dis[temp];
//计算两个点的距离。
cout << ans << endl;
}
}
return 0;
}