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 ; }