这个题好啊
为什么会想到 K r u s k a l Kruskal 重构树呢?
我们最好情况一定是遍历完所有的点,那么最优路线一定是最小生成树
我们能否继续到达某个点很大一部分是根据最小生成树路径上权值最大的边
观察一波 K r u s k a l Kruskal 重构树的性质:
边权越大的形成的点都越靠上
当你到达了一个非叶子节点,就意味着你一定可以到达这个点子树上的所有叶子节点
设一条边为(u,v)如果从u到v 那么一定是将u的子树全部走完了 再加上初始的k 判断能否到v
这样对于每一条边都可以这样 对于一个点只要尽力向上就能获得尽可能大的值 但是一个点只能到他上面路径上要求最大的 不能超过初始的k
这个可以倍增处理
这个题一定不能正面模拟 一定出不了结果的
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N = 1e6+10;
struct Edge1{int u, v, d;}e1[N];
int head[N << 3], idx, a[N << 1];
struct Edge{int to, nxt;}e[N << 3];
void add(int u, int v) {e[++idx].to = v, e[idx].nxt = head[u], head[u] = idx;}
bool cmp(Edge1 _a, Edge1 b) {return _a.d < b.d;}
int f[N << 1];
int find(int n) {return n == f[n] ? n : f[n] = find(f[n]);}
int n, m, q;
int wi[N << 1], fa[N << 1][33], w[N << 1][33];
void dfs(int u, int _f)
{
for (int i = head[u]; i; i = e[i].nxt) {
int v = e[i].to;
if (v == _f) continue;
dfs(v, u);
a[u] += a[v];
}
fa[u][0] = _f, w[u][0] = wi[_f] - a[u];
}
void kruskal()
{
sort(e1 + 1, e1 + 1 + m, cmp);
int cnt = n;
for (int i = 1; i <= m; i++) {
int x = e1[i].u, y = e1[i].v, d = e1[i].d;
x = find(x), y = find(y);
if (x == y) continue;
cnt++;
f[x] = cnt, f[y] = cnt;
add(cnt, x); add(cnt, y); wi[cnt] = d;
}
dfs(cnt, 0);
for (int i = 1; i <= 25; i++) {
for (int j = 1; j <= cnt; j++) {
fa[j][i] = fa[fa[j][i - 1]][i - 1];
w[j][i] = max(w[j][i - 1], w[fa[j][i - 1]][i - 1]);
}
}
}
signed main()
{
cin >> n >> m >> q;
for (int i = 1; i <= n + m; i++) f[i] = i;
for (int i = 1; i <= n; i++) cin >> a[i];
for (int i = 1; i <= m; i++)
cin >> e1[i].u >> e1[i].v >> e1[i].d;
kruskal();
while (q--) {
int x, k;
cin >> x >> k;
for (int i = 24; i >= 0; i--) {
if (fa[x][i]) {
if (w[x][i] <= k) {x = fa[x][i];}
}
}cout << k + a[x] << endl;
}
return 0;
}