[codevs2370]小机房的树

题目大意:给你一棵树,要求两个节点间的最短距离。

解题思路:求出每个询问的LCA,然后每次用前缀和减一减就得到答案了。我用的是倍增,在DFS的时候顺便求前缀和就行了。

C++ Code:

#include<cstdio>
#include<algorithm>
#include<cstring>
using std::swap;
int a[50000+20];
struct edge{
	int dist,next,to;
}e[50000*2+20];
int head[50000*2+20],n,m,deep[50000+20],p[50000+20][20],cnt=0;
void addedge(int x,int y,int c){
	e[++cnt].to=y;
	e[cnt].dist=c;
	e[cnt].next=head[x];
	head[x]=cnt;
	e[++cnt].to=x;
	e[cnt].dist=c;
	e[cnt].next=head[y];
	head[y]=cnt;
}
void dfs(int u){
	for(int i=head[u];i;i=e[i].next)
	if(!deep[e[i].to]){
		deep[e[i].to]=deep[u]+1;
		p[e[i].to][0]=u;
		a[e[i].to]=a[u]+e[i].dist;
		dfs(e[i].to);
	}
}
int lca(int x,int y){
	if(deep[x]<deep[y])swap(x,y);
	int j;
	for(j=0;(1<<j)<=n;++j);j--;
	for(int i=j;i>=0;--i)
	if(deep[p[x][i]]>=deep[y])x=p[x][i];
	if(x==y)return x;
	for(int i=j;i>=0;--i)
	if(p[x][i]!=-1&&p[x][i]!=p[y][i])x=p[x][i],y=p[y][i];
	return p[x][0];
}
int main(){
	scanf("%d",&n);
	for(int i=1;i<n;++i){
		int x,y,c;
		scanf("%d%d%d",&x,&y,&c);
		addedge(x,y,c);
	}
	memset(p,-1,sizeof p);
	a[0]=0;
	deep[0]=1;
	dfs(0);
	for(int j=1;(1<<j)<=n;++j)
	for(int i=1;i<=n;i++)
	if(p[i][j-1]!=-1)p[i][j]=p[p[i][j-1]][j-1];
	scanf("%d",&m);
	while(m--){
		int x,y;
		scanf("%d%d",&x,&y);
		printf("%d
",a[x]+a[y]-2*a[lca(x,y)]);
	}
	return 0;
}
原文地址:https://www.cnblogs.com/Mrsrz/p/7183991.html