题意:n个点m条边,构成的图无环且不一定是一个连通图,q次询问两点间的最短距离
思路:因为给的图其实是一棵树,所以本质上是LCA,套用模板预处理点与点之间的父子关系。将属于同一棵树内的点并到一个点集里,在判断两点的最短路径前先判两点是否在同一点集里。
#include<cstdio>
#include<algorithm>
using namespace std;
const int N = 4e4 + 5;
struct edge {
int to, nex, k;
} es[N << 1];
int head[N], c, dep[N], f[N][20], vis[N], fa[N];
long long dis[N];
void init(int n) {
c = 0;
for(int i = 1; i <= n; i += 1) {
head[i] = -1;
fa[i] = i;
dep[i] = vis[i] = 0;
dis[i] = 0;
}
}
inline void add(int x, int y, int k) {
c += 1;
es[c] = edge{y, head[x], k};
head[x] = c;
}
int find(int x) {
if(x == fa[x])
return x;
else
return fa[x] = find(fa[x]);
}
void Merge(int x, int y) {
int u = find(x);
int v = find(y);
if(u != v) fa[u] = v;
}
void solve(int u, int p) {
dep[u] = dep[p] + 1;
vis[u] = 1;
for(int i = 0; i < 19; i += 1)
f[u][i + 1] = f[f[u][i]][i];
for(int i = head[u]; i != -1; i = es[i].nex) {
int to = es[i].to;
if(to == p || vis[to] )
continue;
f[to][0] = u;
Merge(to, u);
dis[to] = dis[u] + es[i].k;
solve(to, u);
}
}
int lca(int x, int y) {
if(dep[x] < dep[y])
swap(x, y);
for(int i = 19; i >= 0; --i) {
if(dep[f[x][i]] >= dep[y])
x = f[x][i];
if(x == y)
return x;
}
for(int i = 19; i >= 0; --i) {
if(f[x][i] != f[y][i]) {
x = f[x][i];
y = f[y][i];
}
}
return f[x][0];
}
int main() {
int n, e, Q;
while(~scanf("%d%d%d", &n, &e, &Q)) {
init(n);
for(int i = 0; i < e; i += 1) {
int x, y, k;
scanf("%d%d%d", &x, &y, &k);
if(x == y) continue;
add(x, y, k);
add(y, x, k);
}
for(int i = 1; i <= n; i += 1) {
if(!vis[i]) solve(i, 0);
}
while(Q--) {
int x, y;
scanf("%d%d", &x, &y);
if(find(x) != find(y))
printf("Not connected\n");
else
printf("%lld\n", dis[x] + dis[y] - 2 * dis[lca(x,y)]);
}
}
return 0;
}