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