【LuoguP1967】货车运输【生成树】【倍增】

链接

题目大意:

在一张网路上,每条边有一个权重w。

给多次询问x,y,求x到y的路径上最小w的最大值

思路:

容易想到路径一定存在于网络的最大生成树上。

在这颗树上,求两点间最小边权。

用倍增LCA即可完成。

code

cpp 复制代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>

using namespace std;

const int MAXN = 1e5 + 5;

int n, m, q;
int head[MAXN], tot, tot2, Q[MAXN];
int dep[MAXN], f[MAXN][21], dis[MAXN][21];
struct Edge {
    int fro, to, nxt, w;
} E[MAXN << 1], E2[MAXN << 1];

void add(int x, int y, int w) {
    E[++ tot] = (Edge) {x, y, head[x], w};
    head[x] = tot;
}

void add_(int x, int y, int w) {
    E2[++ tot2] = (Edge) {x, y, head[x], w};
    head[x] = tot2;
}

bool cmp(Edge x, Edge y) {
    return x.w > y.w;
}

int Find(int x) {
    if(Q[x] != x) return Q[x] = Find(Q[x]);
    return x;

}

void dfs(int x, int fa) {
    dep[x] = dep[fa] + 1;
    f[x][0] = fa;
    for(int i = head[x]; i; i = E2[i].nxt) {
        int y = E2[i].to;
        if(y == fa) continue;
        dis[y][0] = E2[i].w;
        dfs(y, x);
    }
}

void krus() {
    sort(E + 1, E + 1 + tot, cmp);
    for(int i = 1; i <= n; i ++) Q[i] = i, head[i] = 0;
    for(int i = 1; i <= tot; i ++) {
        int x = E[i].fro, y = E[i].to;
        if(Find(x) != Find(y)) {
            Q[Find(x)] = Find(y);
            add_(x, y, E[i].w), add_(y, x, E[i].w);
        }
    }
}

void RMQ() {
    for(int j = 1; j <= 20; j ++)
        for(int i = 1; i <= n; i ++)
            f[i][j] = f[f[i][j - 1]][j - 1],
            dis[i][j] = min(dis[i][j - 1], dis[f[i][j - 1]][j - 1]);
}

int lca(int x, int y) {
    int ans = 1e9;
    if(dep[x] < dep[y]) swap(x, y);
    int t = dep[x] - dep[y], j = 20;
    while(t) {
        if(t >= (1 << j)) t -= 1 << j, ans = min(ans, dis[x][j]), x = f[x][j];
        j --;
    }
    if(x == y) return ans;
    for(int j = 20; j >= 0; j --) 
        if(f[x][j] != f[y][j]) ans = min(ans, min(dis[x][j], dis[y][j])), x = f[x][j], y = f[y][j];
    return min(ans, min(dis[y][0], dis[x][0]));
}


int main() {
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= m; i ++) {
        int x, y, w;
        scanf("%d%d%d", &x, &y, &w);
        add(x, y, w), add(y, x, w);
    }
    krus();
    for(int i = 1; i <= n; i ++)
        if(!dep[i]) dfs(i, 0);
    RMQ();
    scanf("%d", &q);
    while(q --) {
        int x, y;
        scanf("%d%d", &x, &y);
        int ans = lca(x, y);
        printf("%d\n", ans == 0 ? -1 : ans);
    }
    return 0;
}
相关推荐
怕浪猫1 分钟前
用了两年 AI 编程工具后,我重新理解了什么是「资深工程师」
算法·面试·架构
hetao173383726 分钟前
2026-08-27~29 hetao1733837 的刷题记录
c++·算法
chen<>39 分钟前
C++ 六种 memory_order:从原子性到线程间可见性.md
java·linux·开发语言·c++
云淡风轻~窗明几净44 分钟前
宇宙管理学猜想
算法·图论
会周易的程序员1 小时前
企业私有 AI 算力服务器架构设计:异构四节点 + QUIC 微服务
运维·服务器·c++·人工智能·微服务·架构
春风解人意1 小时前
从零开始学习嵌入式P28----线程
c语言·学习·算法
m0_734571761 小时前
深入理解C++ 类型转换<三>const_cast
开发语言·c++
luj_17681 小时前
合法避税与投资评估实战指南
c语言·开发语言·网络·经验分享·算法
库玛西1 小时前
Linux网络编程:HTTP/HTTPS协议核心技术全解析
linux·运维·服务器·网络·c++·http·https
Bruce_Liuxiaowei2 小时前
驴滑块拼图游戏:从19世纪的纸片谜题到数学博弈论
人工智能·算法