http://acm.hdu.edu.cn/showproblem.php?pid=2586

无根树转有根树,基于rmq算法计算lca,模板题

#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <cmath>
using namespace std ;
const int MAX_V=40005 ;//节点数 
struct edge{int id,to,cost ;} ;//边编号 到达节点 边权值 
vector <edge> G[MAX_V] ;
int dp[100005][20] ;
void makermq(int n,int *tt)
{
    for(int i=0 ;i<n ;i++)
        dp[i][0]=tt[i] ;
    for(int j=1 ;(1<<j)<=n ;j++)
        for(int i=0 ;i+(1<<j)-1<n ;i++)
            dp[i][j]=min(dp[i][j-1],dp[i+(1<<(j-1))][j-1]) ;
} 
int rmq(int l,int r)
{
    int k=(int)(log((r-l+1)*1.0)/log(2)) ;
    return min(dp[l][k],dp[r-(1<<k)+1][k]) ;
}
int root ;//
int vs[MAX_V*2-1] ;//按根的dfs序得到的顶点序列 
int depth[MAX_V*2-1] ;//按根的dfs序得到的顶点序列 对应的深度 
int id[MAX_V] ;// 对于每个节点,在vs中首次出现的下标 
int dis[MAX_V] ;//到根节点距离 
int son[MAX_V] ;//节点的儿子数量  son[i]==0为叶子节点 
int top[MAX_V] ;//和父节点之间边的编号 
int fa[MAX_V] ;//记录父亲节点编号 
void dfs(int v,int p,int d,int &k)
{
    
    id[v]=k ;
    son[v]=0 ;
    vs[k]=v ;
    depth[k++]=d ;
    for(int i=0 ;i<G[v].size() ;i++)
    {
        edge &e=G[v][i] ;
        if(e.to!=p)
        {
            son[v]++ ;
            fa[e.to]=v ;
            top[e.to]=e.id ; 
            dis[e.to]=dis[v]+e.cost ;
            dfs(e.to,v,d+1,k) ;
            vs[k]=v ;
            depth[k++]=d ;
        }
    }
}
void INIT(int V)
{
    memset(dis,0,sizeof(dis)) ;
    int k=0 ;
    dfs(root,-1,0,k) ;
    makermq(V*2-1,depth) ;
}
int lca(int u,int v)
{
    return vs[rmq(min(id[u],id[v]),max(id[u],id[v]))] ;
}
int main()
{
    int t ;
    scanf("%d",&t) ;
    while(t--)
    {
        int n,m ;
        scanf("%d%d",&n,&m) ;
        for(int i=0 ;i<MAX_V ;i++)
            G[i].clear() ;
        for(int i=0 ;i<n-1 ;i++)
        {
            int a,b,w ;
            scanf("%d%d%d",&a,&b,&w) ;
            G[a].push_back((edge){i,b,w}) ;
            G[b].push_back((edge){i,a,w}) ;
        }
        root=1 ;
        INIT(n) ;
        while(m--)
        {
            int a,b ;
            scanf("%d%d",&a,&b) ;
            int p=lca(a,b) ;
            printf("%d\n",dis[a]+dis[b]-2*dis[p]) ;
        }
    }
    return 0 ;
}
View Code