• 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;
    }
    
    
  • 相关阅读:
    有赞个性化推荐能力的演进与实践
    Doge.jpg 的背后是什么,你知道么?
    实操|如何将 Containerd 用作 Kubernetes runtime
    Linux 用键盘操作窗口
    Oracle中join left,join right,inner join,(+) 等
    sql之left join、right join、inner join的区别
    SQL中GROUP BY的用法
    Oracle CASE WHEN 用法介绍
    Oracle数据库面试题
    Oracle笔试题库之问答题篇-总共60道
  • 原文地址:https://www.cnblogs.com/Z8875/p/12859030.html
Copyright © 2020-2023  润新知