HDOJ2586 最近公共祖先模板

版权声明:个人笔记,仅供复习 https://blog.csdn.net/weixin_41162823/article/details/82113549

原题链接:HDOJ2586

解析:用树上倍增法来求LCA

代码实例:

#include<iostream>
#include<cstdio>
#include<queue>
#include<cmath>
#include<cstring>
using namespace std;
const int maxn = 40010;
int f[maxn][20],d[maxn],Dist[maxn];
//依次为:f[i,k]节点i上升2^k次方的节点,d[i]i的深度,Dist[i]i到树根的距离 
int deep;//树的最大深度 
vector<int> G[maxn];//来存放每个点相连的边的编号 
struct Edge{
	int from,to,dist;
};
vector<Edge> edges;
void add_edge(int from,int to,int dist){//如果无向边压入两次 
	edges.push_back(Edge{from,to,dist});
	int m = edges.size()-1;
	G[from].push_back(m);
}
void bfs(){//预处理 
	queue<int> q;
	q.push(1);
	d[1] = 1;
	while(!q.empty()){
		int x = q.front();
		q.pop();	
		for(int i = 0;i < G[x].size();i++){
			Edge& e = edges[G[x][i]];
			if(d[e.to])	continue;
			d[e.to] = d[x] + 1;
			Dist[e.to] = Dist[x] + e.dist;
			f[e.to][0] = x;
			for(int j = 1;j < deep;j++)
				f[e.to][j] = f[f[e.to][j-1]][j-1];
				//e.to向上走2^k步到达的节点等于e.to向上走2^(k-1)步到达的节点再向上走2^(k-1)步 
			q.push(e.to); 
		}
	}
}
int lca(int x,int y){
	if(d[y] < d[x])	swap(x,y); 
	for(int i = deep;i >= 0;i--)//将y上升至和x同一高度 
		if(d[f[y][i]] >= d[x])	y = f[y][i];
	if(x == y)	return x;
	for(int i = deep;i >= 0;i--)//将x和y同时上升2^i个高度,如果相等,说明f[x][0]为答案 
		if(f[x][i] != f[y][i])	x = f[x][i],y = f[y][i];
	return f[x][0];
		
}
void init(int n){
	memset(f,0,sizeof f);
	memset(d,0,sizeof d);
	memset(Dist,0,sizeof Dist);
	edges.clear();
	for(int i = 0;i <= n;i++)	G[i].clear();
}
int main()
{
	int t;
	scanf("%d",&t);
	while(t--){
		int n,m;
		scanf("%d%d",&n,&m);
		init(n);
		deep = (int)(log(n)/log(2))+1;
	
		for(int i = 0;i < n-1;i++){
			int x,y,z;
			scanf("%d%d%d",&x,&y,&z);
			add_edge(x,y,z);
			add_edge(y,x,z);
		}
		bfs();
		for(int i = 0;i < m;i++){
			int x,y;
			scanf("%d%d",&x,&y);
			printf("%d\n",Dist[x]+Dist[y]- 2*Dist[lca(x,y)]);
		}
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_41162823/article/details/82113549