zoukankan      html  css  js  c++  java
  • bzoj 3732: Network 树上两点边权最值

    http://www.lydsy.com/JudgeOnline/problem.php?id=3732

    首先想到,要使得最长边最短,应该尽量走最短的边,在MST上。

    然后像LCA那样倍增娶个最大值

    #include <bits/stdc++.h>
    #define IOS ios::sync_with_stdio(false)
    using namespace std;
    #define inf (0x3f3f3f3f)
    typedef long long int LL;
    const int maxn = 30000 + 20;
    struct Edge {
        int u, v, w, tonext;
        bool operator < (const struct Edge & rhs) const {
            return w < rhs.w;
        }
    } e[maxn], t[maxn];
    int first[maxn], num;
    void addEdge(int u, int v, int w) {
        e[num].u = u, e[num].v = v, e[num].w = w, e[num].tonext = first[u];
        first[u] = num++;
    }
    int tfa[maxn];
    int tofind(int u) {
        if (tfa[u] == u) return u;
        else return tfa[u] = tofind(tfa[u]);
    }
    const int need = 20;
    int mx[maxn][25];
    int ansc[maxn][25], deep[maxn], fa[maxn];  //所有只需初始值,不需要初始化。
    void init_LCA(int cur) {   //1 << 20就有1048576(1e6)了。
        ansc[cur][0] = fa[cur]; //跳1步,那么祖先就是爸爸
        if (cur != 1) {
            for (int i = first[fa[cur]]; ~i; i = e[i].tonext) {
                int v = e[i].v;
                if (v == cur) {
                    mx[cur][0] = e[i].w;
                    break;
                }
            }
        }
        int haha = mx[cur][0];
        for (int i = 1; i <= need; ++i) { //倍增思路,递归处理
            ansc[cur][i] = ansc[ansc[cur][i - 1]][i - 1];
            mx[cur][i] = mx[ansc[cur][i - 1]][i - 1];
            mx[cur][i] = max(mx[cur][i], haha);
            haha = max(haha, mx[cur][i]);  //上到极限的时候需要取个路经的最大值。
        }
        for (int i = first[cur]; ~i; i = e[i].tonext) {
            int v = e[i].v;
            if (v == fa[cur]) continue;
            fa[v] = cur;
            deep[v] = deep[cur] + 1;
            init_LCA(v);
        }
    }
    int LCA(int x, int y) {
        int res = 0;
        if (deep[x] < deep[y]) swap(x, y); //需要x是最深的
        for (int i = need; i >= 0; --i) { //从大到小枚举,因为小的更灵活
            if (deep[ansc[x][i]] >= deep[y]) { //深度相同,走进去就对了。就是要去到相等。
                res = max(res, mx[x][i]);
                x = ansc[x][i];
            }
        }
        if (x == y) return res;
        for (int i = need; i >= 0; --i) {
            if (ansc[x][i] != ansc[y][i]) { //走到第一个不等的地方,
                res = max(res, mx[x][i]);
                res = max(res, mx[y][i]);
                x = ansc[x][i];
                y = ansc[y][i];
            }
        }
        res = max(res, mx[x][0]);
        res = max(res, mx[y][0]);
        return res; //再跳一步就是答案
    }
    
    
    void work() {
        num = 0;
        memset(first, -1, sizeof first);
        int n, m, k;
        scanf("%d%d%d", &n, &m, &k);
        for (int i = 1; i <= n; ++i) tfa[i] = i;
        for (int i = 1; i <= m; ++i) {
            scanf("%d%d%d", &t[i].u, &t[i].v, &t[i].w);
        }
        sort(t + 1, t + 1 + m);
        int sel = 0;
        for (int i = 1; i <= m; ++i) {
            if (sel == n - 1) break;
            int x = tofind(t[i].u), y = tofind(t[i].v);
            if (x == y) continue;
            sel++;
            tfa[y] = x;
            addEdge(t[i].u, t[i].v, t[i].w);
            addEdge(t[i].v, t[i].u, t[i].w);
        }
        fa[1] = 1, deep[1] = 0;
        init_LCA(1);
    //    printf("%d
    ", mx[2][1]);
        for (int i = 1; i <= k; ++i) {
            int u, v;
            scanf("%d%d", &u, &v);
            printf("%d
    ", LCA(u, v));
        }
    }
    
    int main() {
    #ifdef local
        freopen("data.txt", "r", stdin);
    //    freopen("data.txt", "w", stdout);
    #endif
        work();
        return 0;
    }
    View Code
  • 相关阅读:
    Docker | 第二章:第一个Docker应用
    Docker | 第一章:Docker简介
    Docker | 第零章:前言
    SpringBoot | 第十五章:基于Postman的RESTful接口测试
    SpringBoot | 第十四章:基于Docker的简单部署
    SpringBoot | 第十三章:测试相关(单元测试、性能测试)
    2014年计划
    学习方法,工作方法 探讨
    2013年总结
    asp.net用Zxing库实现条形码输出
  • 原文地址:https://www.cnblogs.com/liuweimingcprogram/p/7392488.html
Copyright © 2011-2022 走看看