The Shortest Statement

题目

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;
}

原文地址:https://www.cnblogs.com/shawk/p/12859030.html