#include using namespace std; const int N = 10010, M = N << 1; typedef pair PII; // 查询数组,first:对端节点号,second:问题序号 // 比如:q[2]={5,10} 表示10号问题,计算2和5之间的最短距离 vector query[N]; int dist[N]; // dist[u]记录从出发点S到u的距离 int res[M]; // 结果数组,有多少个问题就有多少个res[i] // 链式前向星 int e[M], h[N], idx, w[M], ne[M]; void add(int a, int b, int c = 0) { e[idx] = b, ne[idx] = h[a], w[idx] = c, h[a] = idx++; } // 并查集 int p[N]; int find(int x) { if (x != p[x]) p[x] = find(p[x]); return p[x]; } int st[N]; // 0:未入栈, 1:在栈中, 2:已出栈 void tarjan(int u) { // ① 标识u已访问 st[u] = 1; // ② 枚举与u临边相连并且没有访问过的点 for (int i = h[u]; ~i; i = ne[i]) { int v = e[i]; if (!st[v]) { // 扩展:更新距离 dist[v] = dist[u] + w[i]; // 深搜 tarjan(v); // ③ v加入u家族 p[v] = u; } } // ④ 枚举已完成访问的点,记录lca或题目要求的结果 for (auto q : query[u]) { int v = q.first, id = q.second; if (st[v] == 2) res[id] = dist[u] + dist[v] - 2 * dist[find(v)]; } // 表示该点已经回溯 st[u] = 2; } int main() { int n, m; // n个结点,m次询问 scanf("%d%d", &n, &m); memset(h, -1, sizeof h); // 初始化链式前向星 for (int i = 1; i <= n; i++) p[i] = i; // 并查集初始化 for (int i = 1; i < n; i++) { // 树有n-1条边 int a, b, c; scanf("%d%d%d", &a, &b, &c); add(a, b, c), add(b, a, c); // 无向图 } // Tarjan算法是离线算法,一次性读入所有的问题,最终一并回答 for (int i = 0; i < m; i++) { // m个询问 int a, b; scanf("%d%d", &a, &b); // 表示询问点 a 到点 b 的最短距离 query[a].push_back({b, i}), query[b].push_back({a, i}); // 不知道谁先被遍历 所以正反都记一下着 } // tarjan算法求LCA tarjan(1); // 回答m个问题 for (int i = 0; i < m; i++) printf("%d\n", res[i]); return 0; }