How far away ? HDU - 2586 (LCA倍增)

How far away ?

 HDU - 2586 

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;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章