[HDU--2586] How far away ? 倍增LCA

 

Problem Description

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

题目大意:给一个无根树,有q个询问,每个询问两个点,问两点的距离。
思路 : 应该是LCA的裸题,因为是树求一下最近公共祖节点,然后记录一下路径长度就行了,但是因为是无根树,所以需要选一个点作为根节点,我选 1 号节点

AC code:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#include <cmath>

using namespace std;

const int maxn = 4e4+50;
const int logtwo = 30;

struct edge{
	int to ,w ;
	edge(){}
	edge(int _w,int _to){ w = _w; to = _to; }
};

vector<edge>G[maxn];
int grand[maxn][logtwo],depth[maxn],gw[maxn][logtwo];
int n,m,N;

void dfs(int x) {
	for (int i = 1;i <= N ; i ++) {
		grand[x][i] = grand[grand[x][i-1]][i-1];
		gw[x][i] = gw[grand[x][i-1]][i-1] + gw[x][i-1];
	}
	int len = G[x].size();
	for (int i = 0;i < len ; i ++ ) {
		edge e = G[x][i];
		if ( grand[x][0] != e.to ) {
			depth[e.to] = depth[x] + 1 ;
			grand[e.to][0] = x; gw[e.to][0] = e.w;
			dfs(e.to);
		}
	}
}

void init() {
	N = floor( log(n + 0.0) / log(2.0) );
	memset(depth,0,sizeof(depth));
	memset(grand,0,sizeof(grand));
	memset(gw,0,sizeof(gw));
	dfs(1);
}

int lca(int a,int b) {
	if ( depth[a] > depth[b] ) swap(a,b);
	int ans = 0;
	for (int i = N;i >= 0;i--) {
		if ( depth[a] < depth[b] && depth[grand[b][i]] >= depth[a] )
			ans += gw[b][i] , b = grand[b][i];
	} 
	for (int j = N; j >= 0 ; j -- ) {
		if ( grand[a][j] != grand[b][j]  ) {
			ans += gw[a][j]; ans += gw[b][j];
			a = grand[a][j]; b = grand[b][j];
		}
	}
	if(a != b) ans += gw[a][0], ans += gw[b][0];
	return ans;
}

int main(){
	int t; cin>>t;
	while ( t -- ) {
		scanf("%d %d",&n,&m);
		for (int i = 0;i <= n;i++) G[i].clear();
		int u,v,w;
		for ( int i = 0; i < n-1 ; i ++ ) {
			scanf("%d %d %d",&u,&v,&w);
			G[u].push_back(edge(w,v));
			G[v].push_back(edge(w,u));
		}
		init();  int a ,b ;
		for (int i = 1;i <= m; i ++ ) {
			scanf("%d %d",&a,&b);
			printf("%d\n",lca(a,b));
		}
	}	
	return 0;
}

补充后来又学了一种板子感觉比以前的好用

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

const int maxn = 4e4 + 50 ;
const int logtwo = 30 ;

struct edge {
	int nxt ,w ,to ;
}ss[maxn << 2];

int head[maxn] ,depth[maxn] ,father[maxn][logtwo] ,fw[maxn] ;
int n ,m ,cnt ,u ,v ,w ,s1 ,s2 ;

void init() {
	cnt = 0;
	memset(depth ,0 ,sizeof(depth)) ;
	memset(fw ,0 ,sizeof(fw)) ;
	memset(father ,0 ,sizeof(father)) ;
	memset(head ,-1 ,sizeof(head)) ;
}

void _add(int u,int v,int w) {
	ss[++cnt].w = w;
	ss[cnt].to = v;
	ss[cnt].nxt = head[u];
	head[u] = cnt ;
}

void add_edge(int u,int v,int w) {
	_add(u ,v ,w) ;
	_add(v ,u ,w ) ;
}

void dfs(int x) {
	for (int i = 1 ; (1 << i) <= depth[x] ; i ++ ) {
		father[x][i] = father[father[x][i-1]][i-1];
	}
	for (int i = head[x] ; ~i ; i = ss[i].nxt ) {
		int v = ss[i].to ;
		if ( v != father[x][0] ) {
			father[v][0] = x;
			depth[v] = depth[x] + 1;
			fw[v] = fw[x] + ss[i].w ;
			dfs(v ) ;
		}
	}
}

int lca(int a,int b) {
	if ( depth[a] > depth[b] ) swap(a ,b ) ;
	int dis = depth[b] - depth[a] ;
	for (int i = 0 ; (1<<i) <= dis ; i ++ ) {
		if ( dis & ( 1 << i) ) {
			b = father[b][i];
		}
	}
	if ( a == b ) return a;
	for (int i = 29 ; i >= 0 ; i -- ) {
		if ( father[a][i] != father[b][i] ) {
			a = father[a][i];
			b = father[b][i];
		}
	}
	return father[a][0];
}

int main() {
	int t; cin >> t ;
	while( t -- ) {
		init() ;
		scanf("%d %d",&n,&m);
		for (int i = 1 ; i < n  ; i ++ ) {
			scanf("%d %d %d",&u ,&v ,&w ) ;
			add_edge(u ,v ,w );
		}
		dfs(1) ;
		for (int i = 1 ; i <= m ; i ++ ) {
			scanf("%d %d",&s1 ,&s2 ) ;
			printf("%d\n",fw[s1] + fw[s2] - 2 * fw[lca(s1 ,s2 )] );
		} 
	}
	return 0;
}
posted @ 2018-08-24 16:28  Nlifea  阅读(107)  评论(0编辑  收藏  举报