zoukankan      html  css  js  c++  java
  • 货车运输 洛谷P1967

    题目链接

    题目描述

    (A)国有$n $座城市,编号从 $ 1 $ 到 $ n $,城市之间有 (m) 条双向道路。每一条道路对车辆都有重量限制,简称限重。现在有 (q) 辆货车在运输货物, 司机们想知道每辆车在不超过车辆限重的情况下,最多能运多重的货物。

    输入输出格式

    输入格式:

    第一行有两个用一个空格隔开的整数$ n,m$,表示 (A) 国有$ n$ 座城市和 (m) 条道路。
    接下来 (m)行每行$ 3 $个整数 (x, y, z),每两个整数之间用一个空格隔开,表示从 $x (号城市到) y $号城市有一条限重为 (z) 的道路。
    注意:(x) 不等于 (y),两座城市之间可能有多条道路。
    接下来一行有一个整数 q,表示有 q 辆货车需要运货。
    接下来 q 行,每行两个整数 x、y,之间用一个空格隔开,表示一辆货车需要从 x 城市运输货物到 y 城市。
    注意:x 不等于 y。

    输出格式:

    共有 (q) 行,每行一个整数,表示对于每一辆货车,它的最大载重是多少。如果货车不能到达目的地,输出(-1)

    数据范围:

    对于 $ 30 % $ 的数据,(0 < n < 1,000,0 < m < 10,000,0 < q< 1,000)
    对于 $ 60 % $ 的数据,(0 < n < 1,000,0 < m < 50,000,0 < q< 1,000)
    对于 $ 100 % $ 的数据,(0 < n < 10,000,0 < m < 50,000,0 < q< 30,000,0 ≤ z ≤ 100,000)

    样例

    样例一输入:

    4 3
    1 2 4
    2 3 3
    3 1 1
    3
    1 3
    1 4
    1 3
    

    样例一输出:

    3
    -1
    3
    

    思路

    1.倍增,最小(da)生成树

    显然,所有的车走过的路径,构成了一颗树
    因为题目要求最小值最大
    所以对原图构造最大生成树
    然后在树上跑lca,倍增维护一下最小值就可以了
    还有就是注意当两点不在一个联通块内判无解

    #include <algorithm>
    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <cmath>
    #include <queue>
    #include <list>
    #include <map>
    
    #define ll long long
    #define ull unsigned long long
    
    using namespace std;
    
    const int mx_n = 101000;
    int n,m,q;
    int dep[mx_n];
    int bcj[mx_n];
    int fa[mx_n][20],le[mx_n][20];
    int h[mx_n],to[mx_n<<1],nx[mx_n<<1],w[mx_n<<1],cnt;
    
    struct stu {
        int u,v;
        int le;
        bool operator < (const stu&a)const {
            return le > a.le;
        }
    } arr[501000];
    
    inline void add(int f,int t,int co) {
        nx[++cnt] = h[f]; h[f] = cnt; to[cnt] = t; w[cnt] = co;
        nx[++cnt] = h[t]; h[t] = cnt; to[cnt] = f; w[cnt] = co;
    }
    
    int f(int x) {
        return bcj[x] == x ? x : bcj[x] = f(bcj[x]);
    }
    
    void dfs(int x) {
        for(int i = h[x]; i; i = nx[i])
            if(to[i] != fa[x][0]) {
                fa[to[i]][0] = x;
                le[to[i]][0] = w[i];
                dep[to[i]] = dep[x] + 1;
                dfs(to[i]);
            }
    }
    
    int LCA(int x,int y) {
        if(f(x) != f(y)) return -1;
        int mn = 0x3f3f3f3f;
        if(dep[x] < dep[y]) swap(x,y);
        for(int i = 19; i >= 0; i--)
            if(dep[fa[x][i]] >= dep[y]) {
                mn = min(mn,le[x][i]);
                x = fa[x][i];
            }
        if(x == y) return mn;
        for(int i = 19; i >= 0; i--)
            if(fa[x][i] != fa[y][i]) {
                mn = min(mn,min(le[x][i],le[y][i]));
                x = fa[x][i];
                y = fa[y][i];
            }
        return min(mn,min(le[x][0],le[y][0]));
    }
    
    int main() {
        scanf("%d%d",&n,&m);
        for(int i = 1; i <= n; i++) bcj[i] = i;
        for(int i = 1; i <= m; i++)
            scanf("%d%d%d",&arr[i].u,&arr[i].v,&arr[i].le);
        sort(arr+1,arr+1+m);
        for(int i = 1; i <= m; i++) {
            int u = arr[i].u;
            int v = arr[i].v;
            int co = arr[i].le;
            if(f(bcj[u]) != f(bcj[v])) {
                bcj[f(u)] = f(v);
                add(u,v,co);
            }
        }
        for(int i = 1; i <= n; i++)
            if(!dep[i]) {
                dep[i] = 1;
                dfs(i);
            }
        for(int i = 1; i <=19; i++)
            for(int j = 1; j <= n; j++) {
                fa[j][i] = fa[fa[j][i-1]][i-1];
                le[j][i] = min(le[j][i-1],le[fa[j][i-1]][i-1]);
            }
        int x,y;
        scanf("%d",&q);
        for(int i = 1; i <= q; i++) {
            scanf("%d%d",&x,&y);
            printf("%d
    ",LCA(x,y));
        }
    }
    
  • 相关阅读:
    e家modem共享上网方法
    千里奔丧
    解决dbvisualizer乱码问题Ubuntu手记之软件
    目录结构Ubuntu手记之系统配置
    javaFTP编程
    JAVA运行环境设置
    VPNCUbuntu手记之软件
    清洗节气门
    IPMSGUbuntu手记之软件
    AIX下的JAVA线程监视
  • 原文地址:https://www.cnblogs.com/ullio/p/9866507.html
Copyright © 2011-2022 走看看