题目
You are given a weighed undirected connected graph, consisting of (n) vertices and (m) edges.
You should answer (q) queries, the (i)-th query is to find the shortest distance between vertices (u_i) and (v_i).
Input
The first line contains two integers (n) and (m (1≤n,m≤10^5,m−n≤20)) — the number of vertices and edges in the graph.
Next (m) lines contain the edges: the (i)-th edge is a triple of integers (v_i,u_i,d_i (1≤u_i,v_i≤n,1≤d_i≤10^9,u_i≠v_i)). This triple means that there is an edge between vertices (u_i) and (v_i) of weight (d_i). It is guaranteed that graph contains no self-loops and multiple edges.
The next line contains a single integer (q (1≤q≤10^5)) — the number of queries.
Each of the next q lines contains two integers (u_i) and (v_i (1≤u_i,v_i≤n)) — descriptions of the queries.
Pay attention to the restriction (m−n ≤ 20).
Output
Print (q) lines.
The (i)-th line should contain the answer to the (i)-th query — the shortest distance between vertices (u_i) and (v_i).
Examples
Input 1
3 3
1 2 3
2 3 1
3 1 5
3
1 2
1 3
2 3
Output 1
3
4
1
Input 2
8 13
1 2 4
2 3 6
3 4 1
4 5 12
5 6 3
6 7 8
7 8 7
1 4 1
1 8 3
2 6 9
2 7 1
4 6 3
6 8 2
8
1 5
1 7
2 3
2 8
3 7
3 4
6 8
7 8
Output 2
7
5
6
7
7
1
2
7
题解
解题思路
对于这道题,跑n遍最短路会超时的
题目中有一个特殊的条件 (m−n ≤ 20).
就是说这个图只比树最多多42条边
就可以根据lca和dij求最短路
代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int MN = 2 * 1e5 + 10;
int N, M, Q, head[MN], num = 0, v[MN], f[MN][21], dp[MN], hp[MN];
int d[50][MN], Tdis[MN];
vector<int> p;
struct Edge {
int u, v, w, f, next;
}e[MN];
inline void add(int x, int y, int z) {
e[num] = (Edge) {x, y, z, 0, head[x]};
head[x] = num++;
}
void dfs(int x, int _fa) {
v[x] = 1; dp[x] = dp[_fa] + 1;
for(int i = head[x]; ~i; i = e[i].next) {
int to = e[i].v;
if(v[to]) continue;
e[i].f = e[i ^ 1].f = 1;
Tdis[to] = Tdis[x] + (int)e[i].w;
f[to][0] = x;
dfs(to, x);
}
}
void Dij(int x, int id) {
memset(v, 0, sizeof(v));
d[id][x] = 0;
priority_queue<pair<int, int> > q; q.push(make_pair(0, x));
while(!q.empty()) {
int p = q.top().second; q.pop();
if(v[p]) continue;
v[p] = 1;
for(int i = head[p]; ~i; i = e[i].next) {
int to = e[i].v;
if(d[id][to] > d[id][p] + e[i].w && (!v[to]))
d[id][to] = d[id][p] + e[i].w, q.push(make_pair(-d[id][to], to));
}
}
}
int lca(int x, int y) {
if(dp[x] < dp[y]) swap(x, y);
for(int i = 20; i >= 0; i--)
if(dp[f[x][i]] >= dp[y]) x = f[x][i];
if(x == y) return x;
for(int i = 20; i >= 0; i--)
if(f[x][i] != f[y][i])
x = f[x][i], y = f[y][i];
return f[x][0];
}
signed main(){
memset(head, -1, sizeof(head));
scanf("%lld%lld", &N, &M);
for(int i = 1; i <= M; i++) {
int x, y, z;
scanf("%lld%lld%lld", &x, &y, &z);
add(x, y, z);
add(y, x, z);
}
dfs(1, 0);
for(int i = 0; i < num; i++)
if(!e[i].f) {
if(!hp[e[i].u]) p.push_back(e[i].u), hp[e[i].u] = 1;
if(!hp[e[i].v]) p.push_back(e[i].v), hp[e[i].v] = 1;
}
memset(d, 0x7f, sizeof(d));
for(int i = 0; i < p.size(); i++)
Dij(p[i], i);
for(int j = 1; j <= 20; j++)
for(int i = 1; i <= N; i++)
f[i][j] = f[f[i][j - 1]][j - 1];
scanf("%lld", &Q);
while(Q--) {
int x, y;
scanf("%lld%lld", &x, &y);
int ans = Tdis[x] + Tdis[y] - 2 * Tdis[lca(x, y)];
for(int i = 0; i < p.size(); i++)
ans = min(ans, d[i][x] + d[i][y]);
cout << ans << endl;
}
return 0;
}