原题链接:HDOJ2586
解析:用树上倍增法来求LCA
代码实例:
#include<iostream>
#include<cstdio>
#include<queue>
#include<cmath>
#include<cstring>
using namespace std;
const int maxn = 40010;
int f[maxn][20],d[maxn],Dist[maxn];
//依次为:f[i,k]节点i上升2^k次方的节点,d[i]i的深度,Dist[i]i到树根的距离
int deep;//树的最大深度
vector<int> G[maxn];//来存放每个点相连的边的编号
struct Edge{
int from,to,dist;
};
vector<Edge> edges;
void add_edge(int from,int to,int dist){//如果无向边压入两次
edges.push_back(Edge{from,to,dist});
int m = edges.size()-1;
G[from].push_back(m);
}
void bfs(){//预处理
queue<int> q;
q.push(1);
d[1] = 1;
while(!q.empty()){
int x = q.front();
q.pop();
for(int i = 0;i < G[x].size();i++){
Edge& e = edges[G[x][i]];
if(d[e.to]) continue;
d[e.to] = d[x] + 1;
Dist[e.to] = Dist[x] + e.dist;
f[e.to][0] = x;
for(int j = 1;j < deep;j++)
f[e.to][j] = f[f[e.to][j-1]][j-1];
//e.to向上走2^k步到达的节点等于e.to向上走2^(k-1)步到达的节点再向上走2^(k-1)步
q.push(e.to);
}
}
}
int lca(int x,int y){
if(d[y] < d[x]) swap(x,y);
for(int i = deep;i >= 0;i--)//将y上升至和x同一高度
if(d[f[y][i]] >= d[x]) y = f[y][i];
if(x == y) return x;
for(int i = deep;i >= 0;i--)//将x和y同时上升2^i个高度,如果相等,说明f[x][0]为答案
if(f[x][i] != f[y][i]) x = f[x][i],y = f[y][i];
return f[x][0];
}
void init(int n){
memset(f,0,sizeof f);
memset(d,0,sizeof d);
memset(Dist,0,sizeof Dist);
edges.clear();
for(int i = 0;i <= n;i++) G[i].clear();
}
int main()
{
int t;
scanf("%d",&t);
while(t--){
int n,m;
scanf("%d%d",&n,&m);
init(n);
deep = (int)(log(n)/log(2))+1;
for(int i = 0;i < n-1;i++){
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
add_edge(x,y,z);
add_edge(y,x,z);
}
bfs();
for(int i = 0;i < m;i++){
int x,y;
scanf("%d%d",&x,&y);
printf("%d\n",Dist[x]+Dist[y]- 2*Dist[lca(x,y)]);
}
}
return 0;
}