【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;
}
相关推荐
周末也要写八哥26 分钟前
经典算法实例:游戏中弱角色的数量(二)
算法
是Yu欸41 分钟前
鸿蒙PC移植:2048 从网页小游戏到 AI 桌面应用
大数据·人工智能·算法·数据挖掘·openharmony·codex
鹿角片ljp1 小时前
KV Cache 解析
java·算法
liliangcsdn1 小时前
IVOL与偏度因子的对比测量分析
算法
qq_199886872 小时前
第6板块·第4节:构建系统与多文件项目
c++·人工智能·gpu算力
threerocks3 小时前
Jev 入门第一课
算法
汉克老师3 小时前
GESP2026年9月认证C++三级( 第三部分编程题(2、分割字符串))精讲
c++·gesp·小学生·学c++编程
估值探索者3 小时前
【Python量化系统工程化 #08】关了 SSH 就停?systemd 让脚本开机自启 + 异常自动拉起
java·c++·人工智能·分类·数据挖掘
西柚研究生1234563 小时前
论文分析17:YOLOv11_UAVNet:无人机航拍图像专用目标检测算法
人工智能·python·深度学习·算法·目标检测
天若有情6734 小时前
C++花式魔改!手写头文件复刻Java语法,彻底打破编码思维定式
java·c++·语言做语言·jac++