用DFS和RMQ实现LCA步骤:
1.E[1]..E[2n-1]表示dfs的过程中经历的所有点
2.id[i]表示点i在E[]中第一次出现的位置,即在dfs中第一次出现的位置
3.任意2点x,y的LCA就是id[x]...id[y]区间中,深度最小的那个点,使用RMQ预处理即可。
ps:
1.E[..]和ST[..][20]都要开2 * n
#include <cstdio>
#include <iostream>
#include <vector>
#include <cstring>
using namespace std;
const int maxn = 5e4 + 5;
int n;
int a,b,c;
struct edge{
int v,w,next;
}es[maxn * 2];//双向边
int head[maxn],cnt = 0;
int id[maxn];
int te = 1;
int dep[maxn];
int E[maxn * 2];//E[1]...E[2n-1]记录dfs路径
int ST[maxn * 2][20];//根据E[i]进行预处理,所以也要开2倍
void addedge(int u,int v,int w)
{
es[cnt].v = v;
es[cnt].w = w;
es[cnt].next = head[u];
head[u] = cnt ++;
}
void dfs(int u,int f)
{
E[te ++] = u;
for (int i = head[u]; i != -1; i = es[i].next) {
edge &e = es[i];
int v = e.v;
if(v == f) continue;
if(dep[v] == -1){
dep[v] = dep[u] + e.w;
dfs(v,u);
E[te ++] = u;
}
}
}
void init_ST()
{
for(int i = 1;i <= n * 2 - 1;i ++) ST[i][0] = E[i];//
for(int j = 1;(1 << j) <= n * 2 - 1;j ++){
for(int i = 1;i + (1 << j) - 1 <= n * 2 - 1;i ++){
int x = ST[i][j - 1],y = ST[i + (1 << (j - 1))][j - 1];
if(dep[x] < dep[y]) ST[i][j] = x;
else ST[i][j] = y;
}
}
}
int query(int l,int r)
{
if(l > r) swap(l, r);
int k = 0;
while(1 << (k + 1) <= r - l + 1) k ++;
int x = ST[l][k],y = ST[r - (1 << k) + 1][k];
if(dep[x] < dep[y]) return x;
else return y;
}
int lca(int x,int y)
{
int a = query(id[x],id[y]);
return dep[x] - dep[a] + dep[y] - dep[a];
}
void init(int n)
{
memset(head, -1, sizeof(head));
cnt = 0;
memset(id,-1,sizeof(id));
memset(dep, -1, sizeof(dep));
te = 1;
memset(ST, 0, sizeof(ST));
memset(E, 0, sizeof(E));
}
bool fg = 0;
int main()
{
while( scanf("%d",&n) != EOF){
if(fg) printf("\n");
fg = 1;
init(n);
for(int i = 0;i < n - 1;i ++){
scanf("%d%d%d",&a,&b,&c);
addedge(a,b,c);
addedge(b, a, c);
}
dep[0] = 0;
dfs(0, -1);
E[te ++] = 0;
for (int i = 1; i <= 2 * n - 1; i ++) {
if(id[E[i]] == -1 ) id[E[i]] = i;
}
init_ST();
int q;scanf("%d",&q);
while(q --){
scanf("%d%d%d",&a,&b,&c);
printf("%d\n",(lca(a,b) + lca(a,c) + lca(b,c)) / 2);
}
}
return 0;
}