hdoj 2586(倍增LCA模板)

题目大意:n结点的树,输出任意两个结点间的最小距离

思路分析:求两个点的LCA,最小距离即deep[a]+deep[b]-2*deep[lca]

#include<iostream>
#include<stdio.h>
#include<string.h>
using namespace std;
const int N=100010;
int h[N],dep[N],fa[N][25];
int nex[N],head[N],p[N],w[N],e;
void add(int u,int v,int x){
     p[e]=v;
     nex[e]=head[u];
     head[u]=e;
     w[e]=x;
     e++;
}
void dfs(int u){
     int v,i;
     for(i=1;i<=21;i++) fa[u][i]=fa[fa[u][i-1]][i-1];
     for(i=head[u];i;i=nex[i]){
         v=p[i];
         if(v!=fa[u][0]){
            fa[v][0]=u;
            h[v]=h[u]+1;
            dep[v]=dep[u]+w[i];
            dfs(v);
         }
     }
}
int lca(int u,int v){
    if(h[u]<h[v]) return lca(v,u);
    int i,d=h[u]-h[v];
    for(i=0;i<=20;i++){
        if((d>>i)&1) u=fa[u][i];
    }
    if(u==v) return u;
    for(i=20;i>=0;i--){
       if(fa[u][i]!=fa[v][i]){
            u=fa[u][i];
            v=fa[v][i];
        }
    }
    return fa[u][0];
}
int main(){
    int t,i,n,m,a,b,c;
    scanf("%d",&t);
    while(t--){
        scanf("%d%d",&n,&m);
        e=1;
        memset(head,0,sizeof(head));
        memset(fa,0,sizeof(fa));
        h[1]=0;
        dep[1]=0;
        for(i=1;i<n;i++){
            scanf("%d%d%d",&a,&b,&c);
            add(a,b,c);
            add(b,a,c);
        }
        dfs(1);
        while(m--){
            scanf("%d%d",&a,&b);
            c=lca(a,b);
            printf("%d\n",dep[a]+dep[b]-2*dep[c]);
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/guogai13/article/details/81256414
今日推荐