• [noip-2013] 货车运输


    https://www.luogu.org/problemnew/show/1967

    /*
        这道题的基本思路在于求最大生成树,构建最大生成树的图
        然后问题相当于转化成求两点之间一条链上的最小值,因为
        这是已经构建出了最大生成树。
        利用倍增的思想,g[i][j]表示i,这个点向上跳j步,这之间
        的最小值,与求lca的f[i][j]很像(基本一样的) 
      自己yy不难理解
    */
    #include <iostream>
    #include <cstdio>
    #include <cmath>
    #include <algorithm>
    #include <cstring>
    #include <string>
    
    using namespace std;
    const int N = 1e4 + 10;
    
    #define oo 99999999
    
    struct Node{
        int u, v, w;
    }S[N * 5];
    struct Edge{
        int u, v, w, nxt;
    }E[N << 1];
    
    int now = 1, n, m, js;
    int head[N], p[N], f[N][25], g[N][25], deep[N];
    
    inline int read(){
        int x = 0; char c = getchar();
        while(c < '0' || c > '9') c = getchar();
        while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
        return x; 
    }
    
    inline bool cmp(Node a, Node b){
        return a.w > b.w;
    }
    
    int getf(int x){
        return p[x] == x ? x : p[x] = getf(p[x]);
    }
    
    void add(int u, int v, int w){
        E[now].v = v;
        E[now].w = w;
        E[now].nxt = head[u];
        head[u] = now ++;
    }
    
    inline void Kruskal(){
        for(int i = 1, doen = 1; i <= (m << 1) && doen < n; i ++){
            int u = S[i].u, v = S[i].v;
            int pu = getf(u), pv = getf(v);
            if(pu != pv){
                p[pu] = pv;
                add(u, v, S[i].w);
                add(v, u, S[i].w);
                doen ++;
            } 
        }
    }
    
    void make_deep(int u, int depth){
        deep[u] = depth;
        for(int i = head[u]; ~ i; i = E[i].nxt){
            int v = E[i].v;
            if(!deep[v]){
                f[v][0] = u;
                g[v][0] = E[i].w;
                make_deep(v, depth + 1);
            } 
        }
    }
    
    inline void make_jump(){
        for(int j = 1; (1 << j) <= n; j ++)
            for(int i = 1; i <= n; i ++)
                if(f[i][j - 1]) f[i][j] = f[f[i][j - 1]][j - 1], g[i][j] = min(g[i][j - 1], g[f[i][j - 1]][j - 1]);
    }
    
    inline int lca(int x, int y){
        int ret = oo;
        if(x == y) return 0;
        if(deep[x] < deep[y]) swap(x, y);
        int k = log2(deep[x]);
        for(int i = k; i >= 0; i --){
            if(deep[f[x][i]] >= deep[y]){
                ret = min(ret, g[x][i]);
                x = f[x][i];
            }
        }
        if(x == y) return ret;
        for(int i = k; i >= 0; i --){
            if(f[x][i] != f[y][i]){
                ret = min(ret, min(g[x][i], g[y][i]));
                x = f[x][i];
                y = f[y][i];
            }
        }
        ret = min(ret, min(g[x][0], g[y][0]));
        return ret;
    }
    
    int main()
    {
        n = read();
        m = read();
        for(int i = 1; i <= n; i ++) head[i] = -1, p[i] = i;
        for(int i = 1; i <= m; i ++) S[i].u = read(), S[i].v = read(), S[i].w = read();
        sort(S + 1, S + m + 1, cmp);
        Kruskal();
        for(int i = 1; i <= n; i ++) if(!deep[i]) make_deep(i, 1); 
        make_jump();
        int T = read();
        while(T --){
            int x = read(), y = read();
            if(getf(x) != getf(y)){
                printf("-1
    ");
                continue ;
            }
            int answer = lca(x, y);
            printf("%d
    ", answer);
        }
        return 0; 
    }
  • 相关阅读:
    poj 1182:食物链(种类并查集,食物链问题)
    hdu 1556:Color the ball(第二类树状数组 —— 区间更新,点求和)
    南阳理工 题目9:posters(离散化+线段树)
    poj 1195:Mobile phones(二维树状数组,矩阵求和)
    poj 3984:迷宫问题(广搜,入门题)
    poj 3278:Catch That Cow(简单一维广搜)
    《重构与模式》简化(策略模式)-积木系列
    builder模式-积木系列
    spring事务管理-Spring 源码系列(6)
    思考如何阅读
  • 原文地址:https://www.cnblogs.com/shandongs1/p/7989653.html
Copyright © 2020-2023  润新知