ICPC 2021上海 H Life is a Game

本文介绍了一种使用C++自定义结构体node简化kruskal算法在构建并查集中重构树的过程,通过实例展示了如何利用mn数组和fa数组存储节点间的路径信息,以及如何高效地查找和更新父节点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

kruskal重构树的题目,一开始没想好怎么建图觉得好烦,最后发现用struct自定义节点node代码就清晰多了。

#include <bits/stdc++.h>
using namespace std;
inline int read() {
    int ret = 0, f = 1; char ch = getchar();
    for (; !isdigit(ch); ch = getchar()) if (ch == '-') f = -f;
    for (; isdigit(ch); ch = getchar()) ret = ret * 10 + ch - 48;
    return ret * f;
}
const int maxn = 1e5 + 5;
const int INF = 0x3f3f3f3f;
int N, M, Q;
int a[maxn], fa[maxn], mp[maxn]; // mp 映射  fa 并查集
int tot; // kruskal重构树节点数
struct node {
    int mn[20]; // 到父节点最少需要多少的初始值
    int fa[20]; // 不同阶的父节点(树上倍增)
    int sm; // 该节点及其子节点所加的分数
} tr[maxn * 2]; // kruskal重构树
struct edge { int x, y, w; } e[maxn];

int getfa(int x) { return fa[x] == x ? x : fa[x] = getfa(fa[x]); }

signed main() {
    N = read(), M = read(), Q = read();
    for (int i = 1; i <= N; ++i) {
        a[i] = read();
        mp[i] = fa[i] = i;
        tr[i].fa[0] = 0, tr[i].sm = a[i];
    }
    for (int i = 1; i <= M; ++i) {
        e[i] = { read(), read(), read() };
    }
    sort(e + 1, e + 1 + M, [](edge a, edge b) {
        return a.w < b.w;
    });
    tot = N;
    for (int i = 1; i <= M; ++i) {
        int &u = e[i].x, &v = e[i].y;
        if (getfa(u) == getfa(v)) continue;
        int &tu = mp[getfa(u)], &tv = mp[getfa(v)];
        ++tot, tr[tot].fa[0] = 0;
        tr[tot].mn[0] = INF;
        tr[tot].sm = tr[tu].sm + tr[tv].sm;
        tr[tu].mn[0] = max(e[i].w - tr[tu].sm, 0);
        tr[tv].mn[0] = max(e[i].w - tr[tv].sm, 0);
        tr[tu].fa[0] = tr[tv].fa[0] = tot;
        fa[getfa(v)] = getfa(u);
        mp[getfa(u)] = tot;
    }
    memset(tr[0].mn, 0, sizeof(tr[0].mn));
    for (int j = 1; (1 << j) <= tot; ++j) {
        for (int i = 1; i <= tot; ++i) {
            tr[i].fa[j] = tr[tr[i].fa[j - 1]].fa[j - 1];
            tr[i].mn[j] = max(tr[i].mn[j - 1], tr[tr[i].fa[j - 1]].mn[j - 1]);
        }
    }
    memset(tr[tot].mn, 0x3f, sizeof(tr[tot].mn));
    while (Q--) {
        int x = read(), k = read(), ans = 0;
        int y = x;
        for (int i = log2(tot); i >= 0; --i) {
            if (tr[y].mn[i] <= k) y = tr[y].fa[i];
        }
        ans = tr[y].sm + k;
        cout << ans << endl;
    }
    return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值