樹上帶權邊,多次查詢兩節點間距離。n ≤ 40000, m ≤ 200, T ≤ 10。
#include
#include
const int MAXN = 40005;
struct Edge { int to, w, next; } e[MAXN * 2];
int head[MAXN], ecnt;
int fa[MAXN], dist[MAXN], lca[MAXN];
bool vis[MAXN];
int q_u[MAXN], q_v[MAXN];
void addEdge(int u, int v, int w) {
e[ecnt] = {v, w, head[u]}; head[u] = ecnt++;
e[ecnt] = {u, w, head[v]}; head[v] = ecnt++;
}
int find(int x) { return fa[x]==x ? x : fa[x]=find(fa[x]); }
void tarjan(int u) {
vis[u] = true; fa[u] = u;
// 處理查詢
for (int i = 1; i <= m; i++) { // 此處假設全局 m, q_u, q_v
if (q_u[i] == u && vis[q_v[i]]) lca[i] = find(q_v[i]);
if (q_v[i] == u && vis[q_u[i]]) lca[i] = find(q_u[i]);
}
// 遞歸子樹
for (int i = head[u]; ~i; i = e[i].next) {
int v = e[i].to;
if (!vis[v]) {
dist[v] = dist[u] + e[i].w;
tarjan(v);
fa[v] = u; // 合併
}
}
}
int main() {
int T; scanf("%d", &T);
while (T--) {
int n, m; scanf("%d%d", &n, &m);
ecnt = 0; memset(head, -1, sizeof(head));
for (int i = 1; i < n; i++) {
int u, v, w; scanf("%d%d%d", &u, &v, &w);
addEdge(u, v, w);
}
for (int i = 1; i <= m; i++) scanf("%d%d", &q_u[i], &q_v[i]);
memset(vis, 0, sizeof(vis));
memset(dist, 0, sizeof(dist));
tarjan(1); // 假設 1 為根
for (int i = 1; i <= m; i++) {
printf("%d\n", dist[q_u[i]] + dist[q_v[i]] - 2 * dist[lca[i]]);
}
if (T) printf("\n"); // 測試用例間空行
}
return 0;
}