题意
T组测试数据,每组给你N,Q,然后给N-1条边(u,v,w)u-v边权为w,表示一棵树,Q次询问,每次询问a到b的最短路径。
思路
LCA,然后过程中记录下每个点到根节点的距离dis,dis[a] + dis[b] - 2*dis[LCA(a,b)]就是a到b的最短路径。
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1e5 + 5;
struct Edge
{
int from, to, dist;
Edge (int from, int to, int dist): from(from), to(to), dist(dist) {}
};
struct Query
{
int id, a, b;
Query (int id, int a, int b): id(id), a(a), b(b) {}
};
//tarjan离线求LCA
struct LCA
{
int n, m, Q_cnt;
int par[MAXN]; //并查集
vector<Edge> edges;
vector<int> G[MAXN];
vector<Query> querys; //查询建图
vector<int> Q[MAXN]; //查询的邻接表
bool vis[MAXN]; //是否被遍历
int lca[MAXN]; //答案
int dis[MAXN]; //到根节点的距离
void init (int n)
{
this->n = n, m = 0, Q_cnt = 0;
edges.clear(), querys.clear();
for (int i = 0; i <= n; i++)
{
G[i].clear(), Q[i].clear();
par[i] = i;
dis[i] = vis[i] = 0;
}
}
void AddEdge (int from, int to, int dist)
{
edges.emplace_back(from, to, dist);
edges.emplace_back(to, from, dist);
m = edges.size();
G[from].push_back(m-2);
G[to].push_back(m-1);
}
void AddQuery (int id, int u, int v)
{
querys.emplace_back(id, u, v);
querys.emplace_back(id, v, u);
Q_cnt = querys.size();
Q[u].push_back(Q_cnt-2);
Q[v].push_back(Q_cnt-1);
}
int Find (int x) { return x == par[x] ? x : par[x] = Find(par[x]); }
void unite (int x, int y)
{
int rt1 = Find(x), rt2 = Find(y);
if (rt1 != rt2) par[rt2] = rt1;
}
void tarjan(int u)
{
vis[u] = 1;
for (auto& i : G[u])
{
Edge& e = edges[i];
int v = e.to;
if (vis[v]) continue;
dis[v] = dis[u] + e.dist;
tarjan(v);
unite(u, v);
}
for (auto& i : Q[u])
{
Query& q = querys[i];
if (!vis[q.b]) continue;
lca[q.id] = Find(q.b);
}
}
}gao;
int main()
{
int T; scanf("%d", &T);
while (T--)
{
int n, Q; scanf("%d%d", &n, &Q);
gao.init(n);
for (int i = 1; i < n; i++)
{
int u, v, w; scanf("%d%d%d", &u, &v, &w);
gao.AddEdge(u, v, w);
}
for (int i = 0; i < Q; i++)
{
int a, b; scanf("%d%d", &a, &b);
gao.AddQuery(i, a, b);
}
gao.tarjan(1);
for (int i = 0; i < Q; i++)
{
Query& q = gao.querys[i*2];
int ans = gao.dis[q.a] + gao.dis[q.b] - 2*gao.dis[gao.lca[i]];
printf("%d\n", ans);
}
}
return 0;
}
/*
2
3 2
1 2 10
3 1 15
1 2
2 3
2 2
1 2 100
1 2
2 1
*/