How far away ?
There are n houses in the village and some bidirectional roads connecting them. Every day peole always like to ask like this "How far is it if I want to go from house A to house B"? Usually it hard to answer. But luckily int this village the answer is always unique, since the roads are built in the way that there is a unique simple path("simple" means you can't visit a place twice) between every two houses. Yout task is to answer all these curious people.
Input
First line is a single integer T(T<=10), indicating the number of test cases.
For each test case,in the first line there are two numbers n(2<=n<=40000) and m (1<=m<=200),the number of houses and the number of queries. The following n-1 lines each consisting three numbers i,j,k, separated bu a single space, meaning that there is a road connecting house i and house j,with length k(0<k<=40000).The houses are labeled from 1 to n.
Next m lines each has distinct integers i and j, you areato answer the distance between house i and house j.
Output
For each test case,output m lines. Each line represents the answer of the query. Output a bland line after each test case.
Sample Input
2
3 2
1 2 10
3 1 15
1 2
2 3
2 2
1 2 100
1 2
2 1
Sample Output
10
25
100
100
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <cstdio>
#include <cmath>
using namespace std;
const int N = 40007;
const int M = 1e6 + 7;
int head[N], en;
//倍增在线
struct Edge {
int v, w, to;
} e[M];
int grand[N][25]; //grang[i][k]:点i向上跳2^k次方处的点 //祖先节点
long long dist[N][25]; // 点i到它向上跳2^k次方处的点的距离
int deep[N]; //dfs点的深度
int maxd; //最大可跳距离,根据N改变,在2^maxd<=N限制下取最大
void addedge(int u, int v, int w) {
e[++en].v = v;
e[en].w = w;
e[en].to = head[u];
head[u] = en;
e[++en].v = u;
e[en].w = w;
e[en].to = head[v];
head[v] = en;
}
void init(int n) {
memset(head, -1, sizeof(head));
memset(grand, 0, sizeof(grand));
memset(dist, 0, sizeof(dist));
deep[1] = 0;
en = 0;
maxd = floor(log(n+0.0) / log(2.0)); //log2(n)向下取整,最大能跳2^maxd
}
void dfs(int u) { //深搜建图
for (int i = 1; i <= maxd; ++i) { //初始化
grand[u][i] = grand[grand[u][i-1]][i-1]; //2^4 = 2^3 + 2^3
dist[u][i] = dist[u][i-1] + dist[grand[u][i-1]][i-1]; //原理一样
}
for (int i = head[u]; ~i; i = e[i].to) {
int v = e[i].v;
if (v != grand[u][0]) { //v 不能是 u的父节点
deep[v] = deep[u] + 1;
grand[v][0] = u;//2^0 = 1父节点
dist[v][0] = e[i].w;
dfs(v);
}
}
}
//倍增
long long lca(int u, int v) {
if (deep[u] > deep[v]) swap(u, v); //保证a在b上面
long long ans = 0;
for (int i = maxd; i >= 0; --i) { //2^0==1
if (deep[u] < deep[v] && deep[grand[v][i]] >= deep[u]) {//v在u下面且v跳后不会到u之上
ans += dist[v][i]; //加上跳的距离
v = grand[v][i]; //跳
}
}
//深度相同之后, 同时跳
for (int i = maxd; i >= 0; --i) {
if (grand[u][i] != grand[v][i]) { //这时候深度相同,祖先不同,则两个一起跳
ans += dist[u][i];
ans += dist[v][i];
u = grand[u][i];
v = grand[v][i];
}
}
if (u != v) { //还不等,但上面已经不能跳了,说明父节点就是一样的
ans += dist[u][0];
ans += dist[v][0];
}
return ans;
}
int main() {
int t;
scanf ("%d", &t);
while (t--) {
int n, m;
scanf ("%d %d", &n, &m);
int u, v, w;
init(n);
//printf ("maxd: %d\n", maxd);
for (int i = 1; i < n; ++i) {
scanf ("%d %d %d", &u, &v, &w);
addedge (u, v, w);
}
dfs(1);
for (int i = 1; i <= m; ++i) {
scanf ("%d %d", &u, &v);
printf ("%lld\n", lca(u, v));
}
}
return 0;
}