原題鏈接: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;
}