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;
}