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\n", mx[2][1]);
    for (int i = 1; i <= k; ++i) {
        int u, v;
        scanf("%d%d", &u, &v);
        printf("%d\n", LCA(u, v));
    }
}

int main() {
#ifdef local
    freopen("data.txt", "r", stdin);
//    freopen("data.txt", "w", stdout);
#endif
    work();
    return 0;
}
View Code

 

既然选择了远方,就要风雨兼程~

posted on 2017-08-18 22:24  stupid_one  阅读(263)  评论(0编辑  收藏  举报

导航