题目大意:给你一棵树,要求两个节点间的最短距离。
解题思路:求出每个询问的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;
}