题意:求三点之间的最短距离。
思路:三个点之间两两进行 LCA, 得到的结果加起来除以二就是答案。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <vector>
#define mem(x,v) memset(x,v,sizeof(x))
#define rep(i,a,b) for (int i = a; i < b; i++)
#define per(i,a,b) for (int i = a; i > b; i--)
using namespace std;
typedef long long LL;
const double EPS = 1e-10;
const int INF = 0x3f3f3f3f;
const int N = 2e5+10;
struct node
{
int v,w,next;
}g[N];
int n,m,cnt,head[N],dep[N];
int f[N][30],dis[N];
void Add_edge(int u, int v, int w){
cnt++;
g[cnt].next = head[u];
head[u] = cnt;
g[cnt].v = v;
g[cnt].w = w;
return;
}
int lca(int x, int y){
if (dep[x] < dep[y]) swap(x,y);
for (int i = 22; i >= 0; i--)
if (dep[f[x][i]] >= dep[y]) x = f[x][i];
if (x == y) return x;
for (int i = 22; i >= 0; i--)
if (f[x][i] != f[y][i]){
x = f[x][i];
y = f[y][i];
}
return f[x][0];
}
void dfs(int u, int fa, int deep){
f[u][0] = fa;
dep[u] = deep;
for (int i = 1; i < 23; i++)
f[u][i] = f[f[u][i-1]][i-1];
for (int i = head[u]; i != -1; i = g[i].next){
int v = g[i].v;
if (fa == v) continue;
dis[v] = dis[u] + g[i].w;
dfs(v,u,deep+1);
}
return;
}
int clac(int x, int y){
return dis[x] + dis[y] - 2*dis[lca(x,y)];
}
int main(){
int x,y,z;
bool flag = 0;
while(scanf("%d",&n) != EOF){
if (flag) printf("\n");
flag = 1;
mem(head,-1);
cnt = -1;
rep(i,1,n){
scanf("%d%d%d",&x,&y,&z);
Add_edge(x,y,z);
Add_edge(y,x,z);
}
mem(f,0); mem(dis,0); mem(dep,0);
dfs(0,0,0);
scanf("%d",&m);
rep(i,0,m){
scanf("%d%d%d",&x,&y,&z);
int ans = clac(x,y)+clac(y,z)+clac(x,z);
printf("%d\n",ans/2);
}
}
return 0;
}