• The Shortest Statement


    ps:非常非常重要的一个条件 m - n <= 20,考虑图的生成树,那么(u,v)之间的最短路上的边有两种情况,一是最短路不经过非生成树的边,二是经过非生成树的边。又非生成树的边只有20条,则连接的点最多有40个,所以对这40个点分别跑一次DJS,然后取最小值就行了。(换言之:如果最短路经过非生成树边,那么我们就可以枚举这些边)

    const int N = 100005;
    
    int n, m, tot, top;
    int head[N], pa[N][20], dp[N], tp[100];
    
    LL d[N][55];
    
    bool use[N];
    
    struct node { int to, va, next; } e[N * 2];
    
    priority_queue<P, vector<P>, greater<P> > q;
    
    void Inite() {
        top = tot = 0;
        mem(head, -1);
        Rep(i, 1, n) Rep(j, 1, 50) d[i][j] = INF64;
    }
    
    void addedge(int u, int v, int w) {
        e[tot].to = v, e[tot].va = w, e[tot].next = head[u], head[u] = tot++;
    }
    
    void DFS(int u, int p) {
        use[u] = 1;
        pa[u][0] = p;
        for (int i = head[u]; ~i; i = e[i].next) if (e[i].to != p) {
            int v = e[i].to;
            if (use[v]) tp[++top] = v, tp[++top] = u;
            else {
                dp[v] = dp[u] + 1;
                d[v][0] = d[u][0] + e[i].va;
                DFS(v, u);
            }
        }
    }
    
    int Lca(int u, int v) {
        if (u == v) return u;
        if (dp[u] > dp[v]) swap(u, v);
    
        for (int i = 19; ~i; --i) if (dp[pa[v][i]] >= dp[u]) v = pa[v][i];
        //rep(i, 0, 20) if (((1 << i) & (dp[v] - dp[u])) == 1) v = pa[v][i];
        if (u == v) return u;
    
        for (int i = 19; ~i; --i) if (pa[u][i] != pa[v][i]) {
            u = pa[u][i];
            v = pa[v][i];
        }
        return pa[u][0];
    }
    
    void Compute(int id) {
        while(!q.empty()) q.pop();
        bool vis[N];
        mem(vis, 0);
    
        d[tp[id]][id] = 0;
        q.push(P(0, tp[id]));
    
        while(!q.empty()) {
            P p = q.top();
            q.pop();
    
            int v = p.second;
            if (vis[v]) continue;
            vis[v] = 1;
    
            for (int i = head[v]; ~i; i = e[i].next) if (d[e[i].to][id] > d[v][id] + e[i].va) {
                d[e[i].to][id] = d[v][id] + e[i].va;
                q.push(P(d[e[i].to][id], e[i].to));
            }
        }
    }
    
    int main()
    {
        sc(n), sc(m);
    
        Inite();
        Rep(i, 1, m) {
            int u, v, w;
            sc(u), sc(v), sc(w);
            addedge(u, v, w);
            addedge(v, u, w);
        }
    
        DFS(1, 0);
        Rep(i, 1, 19) Rep(j, 1, n) if (pa[j][i - 1]) pa[j][i] = pa[pa[j][i - 1]][i - 1];
    
        sort(tp + 1, tp + top + 1);
        top = unique(tp + 1, tp + top + 1) - (tp + 1);
    
        Rep(i, 1, top) Compute(i);
    
        int cnt;
        sc(cnt);
    
        while(cnt--) {
            int u, v;
            sc(u), sc(v);
    
            int p = Lca(u, v);
            LL ans = d[u][0] + d[v][0] - 2 * d[p][0];
    
            Rep(i, 1, top) ans = min(ans, d[u][i] + d[v][i]);
            pr(ans);
        }
    
        return 0;
    }
  • 相关阅读:
    Redis 哨兵机制以及灾难演练
    经典的Redis的主从复制搭建
    Redis的几个核心机制底层原理
    Redis Sentinel(哨兵核心机制) 初步深入
    从零开始装CentOS以及配置Redis,前端都可以!!!
    在项目中部署redis的读写分离架构(包含节点间认证口令)
    读懂MySQL执行计划
    SpringBoot之自动配置原理
    排序算法总结
    拉格朗日插值法理论与编程实现
  • 原文地址:https://www.cnblogs.com/zgglj-com/p/9696288.html
Copyright © 2020-2023  润新知