【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 小时前
华为云Flexus+DeepSeek征文|Agent 记忆系统实战:用 DeepSeek-R1/V3 + Dify 会话变量打造跨会话长期记忆
人工智能·深度学习·算法·aigc
草莓熊Lotso1 小时前
【Linux网络】从0手写Reactor反应堆(二):完善核心细节——ET非阻塞读写、分层架构与回调机制
linux·运维·服务器·网络·c++·tcp/ip·架构
Olafur_zbj1 小时前
【AI】CUDA编程中的维度
人工智能·算法
cvby1 小时前
C++哈希
c++·哈希算法·散列表
世事如云有卷舒2 小时前
GoogTest测试框架
c++·测试
坚持编程的菜鸟2 小时前
模拟实现memcpy
c语言·算法·模拟实现my_memcpy
wabs6662 小时前
关于图论【最短路径之Bellman_ford 算法|卡码网94.城市间货物运输的思考】
数据结构·算法·图论·卡码网·bellman_ford·求最短路径
MrZhao4002 小时前
On-Policy Distillation(OPD):为什么大模型后训练要在学生自己的轨迹上蒸馏?
算法
朱峥嵘(朱髯)2 小时前
数据库如何根据全表 NDV 估算子集的 NDV
数据库·算法