You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

77 lines
2.3 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#include <bits/stdc++.h>
using namespace std;
const int N = 10010, M = N << 1;
typedef pair<int, int> PII;
// 查询数组first:对端节点号second:问题序号
// 比如:q[2]={5,10} 表示10号问题,计算2和5之间的最短距离
vector<PII> 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;
}