zoukankan      html  css  js  c++  java
  • 「LCA + 最小生成树」货车运输

    货车运输

    原题链接 货车运输

    题目大意

    (n) 个点,然后给你 (m) 条边,每条边我们有边权 (k) ,现在给你 (q) 次询问,每次询问两个整数 (x, y),表示从 (x)(y) 的最大值为多少,这个值就是走过的边权的最小值。

    题目题解

    这道题很明显可以得到的是,一些边我们从始至终都不会走的,因为有别的更优的路径,这让我们想到了最大生成树了,那求出最大生成树之后怎么办呢?我们发现,对于两个点而言,在最大生成树中有且仅有一条路径可以互通,如何让电脑直接走这条路呢,嗯?是不是很熟悉,对,就是LCA,求最近公共祖先,但光只有LCA肯定是不行的,因为我们这次带上了边权,其实问题很简单,根据题目大意我们得到:我们的问题是找到我们走的边的最小边权,那么就意味着我们可以维护一个与记录(x)点的(2^k)的数组一样的数组,维护(x)点走(2^k)后所能得到的最小值,那么这样我们就能得到我们的答案了

    代码如下

    //#define fre yes
    
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define INF 9999999
    
    const int N = 50005;
    struct Node {
        int x, y, z;
    }g[N];
    
    int head[N], to[N], ver[N], edge[N];
    int par[N];
    int depth[N], f[N][22], w[N][22], lg[N];
    bool Vis[N];
    
    int n;
    
    void init() {
        for (int i = 1; i <= n; i++) {
            par[i] = i;
        }
    }
    
    int tot;
    void addedge(int x, int y, int z) {
        ver[tot] = y;
        edge[tot] = z;
        to[tot] = head[x];
        head[x] = tot++;
    }
    
    bool cmp(Node x, Node y) {
        return x.z > y.z;
    }
    
    int find(int x) {
        if(x == par[x]) return par[x];
        else return par[x] = find(par[x]);
    }
    
    void dfs(int x, int fa) {
        Vis[x] = 1;
        depth[x] = depth[fa] + 1;
        f[x][0] = fa;
        for (int i = 1; (1 << i) <= depth[x]; i++) {
            f[x][i] = f[f[x][i - 1]][i - 1];
            w[x][i] = std::min(w[x][i - 1], w[f[x][i - 1]][i - 1]);
        }
    
        for (int i = head[x]; ~i; i = to[i]) {
            int v = ver[i];
            if(v != fa) {
                w[v][0] = edge[i];
                dfs(v, x);
            }
        }
    }
    
    int lca(int x, int y) {
        if(find(x) != find(y)) return -1;
        int ans = INF;
        if(depth[x] < depth[y]) {
            std::swap(x, y);
        }
    
        while(depth[x] > depth[y]) {
            ans = std::min(ans, w[x][lg[depth[x] - depth[y]] - 1]);
            x = f[x][lg[depth[x] - depth[y]] - 1];
        }
    
        if(x == y) return ans;
    
        for (int i = lg[depth[x]] - 1; i >= 0; i--) {
            if(f[x][i] != f[y][i]) {
                ans = std::min(ans, std::min(w[x][i], w[y][i]));
                x = f[x][i];
                y = f[y][i];
            }
        }
    
        ans = std::min(ans, std::min(w[x][0], w[y][0]));
        return ans;
    }
    
    int main() {
        memset(head, -1, sizeof(head));
        memset(w, 0x3f, sizeof(w));
        static int m;
        scanf("%d %d", &n, &m);
        init();
        for (int i = 1; i <= m; i++) {
            int x, y, z;
            scanf("%d %d %d", &x, &y, &z);
            g[i].x = x;
            g[i].y = y;
            g[i].z = z;
        }
    
        std::sort(g + 1, g + 1 + m, cmp);
    
        for (int i = 1; i <= m; i++) {
            int x = find(g[i].x);
            int y = find(g[i].y);
            if(x == y) continue;
    
            par[x] = y;
            addedge(g[i].x, g[i].y, g[i].z);
            addedge(g[i].y, g[i].x, g[i].z);
        }
    
        for (int i = 1; i <= n; i++) {
            if(!Vis[i]) {
                dfs(i, 0);
            }
        }
    
        for (int i = 1; i <= n; i++) {
            lg[i] = lg[i - 1] + (1 << lg[i - 1] == i);
        }
    
        static int t;
        scanf("%d", &t);
        for (int i = 1; i <= t; i++) {
            int x, y;
            scanf("%d %d", &x, &y);
            printf("%d
    ", lca(x, y));
        } return 0;
    }
    
  • 相关阅读:
    你所不知道的setTimeout
    SecureCRT8.1下载+注册机+破解教程
    jQuery学习
    GIt学习
    多进程
    Linux下的压缩(zip)解压(unzip)缩命令
    三次握手四次挥手
    django常见问题
    form和modelform
    文件上传
  • 原文地址:https://www.cnblogs.com/Nicoppa/p/11475593.html
Copyright © 2011-2022 走看看