lca

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

 

你可能感兴趣的:(ca)