• 【noip2013】货车运输 (最大生成树 + 倍增)


    题目描述 Description

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

    输入描述 Input Description

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

    输出描述 Output Description

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

    样例输入 Sample Input

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

    样例输出 Sample Output

    3
    -1
    3

    数据范围及提示 Data Size & Hint

    对于 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。

    题目分析

    首先若两地不联通直接输出-1(并查集判断)。要想限重大,那么一定是在最大生成树上走,剩下的工作就是找出再生成树上x-y的路径上的最小权值,直接枚举边肯定会TLE,考虑使用倍增算法:fa[u][i]表示u向上跳$2^i$后的点是谁,这样fa[u][0]就是父节点。minn[u][i]表示u到fa[u][i]这条路径上的最小权值。dfs时就可以预处理出来,接着就可以像求lca一样求出去最小权值。

    code

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<string>
    #include<algorithm>
    #include<cmath>
    #include<vector>
    using namespace std;
    
    const int N = 1e4 + 5, M = 5e4 + 5, oo = 0x3f3f3f3f;
    int n, m, ecnt, Q;
    struct Edge{
        int u, v, w;
    }edge[M << 1];
    int adj[N], go[M << 1], nxt[M << 1], len[M << 1];
    int anc[N], Log[N];
    int fa[N][30], minn[N][30], dep[N];
    bool vst[N];
    
    inline bool cmp(const Edge &a, const Edge &b){
        return a.w>b.w;
    }
    
    inline void addEdge(int u, int v, int w){
        nxt[++ecnt] = adj[u], adj[u] = ecnt, go[ecnt] = v, len[ecnt] = w;
        nxt[++ecnt] = adj[v], adj[v] = ecnt, go[ecnt] = u, len[ecnt] = w;
    }
    
    inline void dfs(int u){
        for(int i = 1; fa[u][i - 1]; i++){
            fa[u][i] = fa[fa[u][i - 1]][i - 1];
            minn[u][i] = min(minn[u][i - 1], minn[fa[u][i - 1]][i - 1]);
        }
        for(int e = adj[u], v; e; e = nxt[e]){
            if((v = go[e]) == fa[u][0]) continue;
            fa[v][0] = u;
            dep[v] = dep[u] + 1;
            minn[v][0] = len[e];
            dfs(v);
            vst[v] = true;
        }
    }
    
    inline int query(int u, int v){
        if(dep[u] < dep[v]) swap(u, v);
        int delta = dep[u] - dep[v], ret = oo;
        for(int i = Log[delta]; i >= 0; i--)
            if((1 << i) & delta){
                ret = min(ret, minn[u][i]);
                u = fa[u][i];
            }
        if(u == v) return ret;
        for(int i = Log[dep[u]]; i >= 0; i--)
            if(fa[u][i] != fa[v][i]){
                ret = min(ret, min(minn[u][i], minn[v][i]));
                u = fa[u][i], v = fa[v][i];
            }
        ret = min(ret, min(minn[u][0], minn[v][0]));
        return ret;
    }
    
    inline void initLog(){
        Log[0] = -1;
        for(int i = 1; i <= n; i++)
            Log[i] = Log[i >> 1] + 1; 
    }
    
    inline int getAnc(int u){
        return anc[u] == u ? u : (anc[u] = getAnc(anc[u]));
    }
    
    inline int read(){
        int i = 0, f = 1; char ch = getchar();
        for(; (ch < '0' || ch > '9') && ch != '-'; ch = getchar());
        if(ch == '-') f = -1, ch = getchar();
        for(; ch >= '0' && ch <= '9'; ch = getchar())
            i = (i << 3) + (i << 1) + (ch - '0');
        return i * f;
    }
    
    inline void wr(int x){
        if(x < 0) putchar('-'), x = -x;
        if(x > 9) wr(x / 10);
        putchar(x % 10 + '0');
    }
    
    int main(){
        n = read(), m = read();
        initLog();
        for(int i = 1; i <= n; i++) anc[i] = i;
        for(int i = 1; i <= m; i++){
            int x = read(), y = read(), z = read();
            edge[i].u = x, edge[i].v = y, edge[i].w = z;
        }
        sort(edge + 1, edge + m + 1, cmp);
        for(int i = 1; i <= m; i++){
            Edge e = edge[i];
            int f = getAnc(e.u), g = getAnc(e.v);
            if(f != g){
                anc[f] = g; 
                addEdge(e.u, e.v, e.w);
            }
        }
        for(int i = 1; i <= n; i++)
            if(!vst[i]){
                vst[i] = true;
                dfs(i);
            }
        Q = read();
        while(Q--){
            int x = read(), y = read();
            int f = getAnc(x), g = getAnc(y);
            if(f != g)
                wr(-1), putchar('
    ');
            else wr(query(x, y)), putchar('
    ');
        }
        return 0;
    }
  • 相关阅读:
    cookie secure属性 导致setcookie失败-test
    vim 常用操作总结(持续更新)-test
    网页重定向(外部重定向和内部重定向)-test
    pat 1002 A+B for polynomials (第二个测试点一直无法通过,最后解决)-test
    pat 1001 A+B Format-test
    验证码无法显示的其中一种原因-test
    str_replace替换换行符失败原因-test
    .net/C#语言web项目内新增js或css文件调用不到,url报错404
    在W10系统中配置Java环境变量后,cmd命令提示符找不到java
    JS使用知识点理解
  • 原文地址:https://www.cnblogs.com/CzYoL/p/7384990.html
Copyright © 2020-2023  润新知