1 条题解
-
0
自动搬运
来自洛谷,原作者为

5k_sync_closer
数据结构真可爱。搬运于
2025-08-24 22:48:49,当前版本为作者最后更新于2023-07-29 20:56:35,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
出题人题解。
设 为 路径边权和, 为 路径点权和。
题目中求 最小的前提下 最大,
是定值,只需令 最小的前提下 最大。
考虑对每个 路径上的 维护出 最小值以及此时 最大值。
用换根 DP 维护之。设 为 在 子树内时 的最小值 / 次小值,则容易得到状态转移方程:
$$\begin{aligned} f_{p,0}&=\min(\{f_{q,0}+x(p,q)|q\in son_p\}\cup\{0\})\\ f_{p,1}&=\mathop{\operatorname{secondmin}}(\{f_{q,0}+x(p,q)|q\in son_p\}\cup\{0\}) \end{aligned} $$转移时记录 最大值。
设 为 的最小值 / 次小值,则 由 转移而来, 由 转移而来, 可能由 转移而来,存在重复计算。
需要记录 为转移到 的点,从而消除重复计算。
则有状态转移方程:
$$\begin{aligned} g_{p,0}&=\min\{f_{p,0},g_{fa_p,[k_{fa_p}=p]}+x(p,fa_p)\}\\ g_{p,1}&=\mathop{\operatorname{secondmin}}\{f_{p,0},f_{p,1},g_{fa_p,[k_{fa_p}=p]}+x(p,fa_p)\} \end{aligned} $$转移时记录 最大值。
则问题转化为求静态树链最小值,用树上倍增维护之。
#include <cstdio> #include <algorithm> #define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++) using namespace std; char buf[1 << 23], *p1 = buf, *p2 = buf, obuf[1 << 23], *O = obuf; inline int R() { int r = 0; bool f = 0; char c = getchar(); while (c < '0' || c > '9') f = c == '-', c = getchar(); while (c >= '0' && c <= '9') r = r * 10 + c - '0', c = getchar(); return f ? -r : r; } void P(long long x) { if (x < 0) *O++ = '-', x = -x; if (x >= 10) P(x / 10); *O++ = x % 10 + '0'; } struct S { long long x, y, p; S operator+(S b) { return {x + b.x, y + b.y}; } bool operator<(S b) const { return x == b.x ? y > b.y : x < b.x; } } Q, F[300050][2], C[300050][20]; struct E { int v, w, t; } e[1000050]; int n, m, c, a[300050], d[300050], h[300050], f[300050][20]; long long s[300050]; void A(int u, int v, int w) { e[++c] = {v, w, h[u]}; h[u] = c; } void D1(int u) { for (int i = h[u], v; i; i = e[i].t) if (!d[v = e[i].v]) { d[v] = d[u] + 1; f[v][0] = u; for (int i = 1; f[v][i - 1]; ++i) f[v][i] = f[f[v][i - 1]][i - 1]; s[v] = s[u] + a[v]; D1(v); S X = F[v][0] + S{e[i].w, a[v] << 1}; X.p = v; if (X < F[u][0]) F[u][1] = F[u][0], F[u][0] = X; else if (X < F[u][1]) F[u][1] = X; } } void D2(int u, int k) { for (int i = h[u], v; i; i = e[i].t) if ((v = e[i].v) != k) { S X = F[u][F[u][0].p == v] + S{e[i].w, a[u] << 1}; X.p = u; if (X < F[v][0]) F[v][1] = F[v][0], F[v][0] = X; else if (X < F[v][1]) F[v][1] = X; D2(v, u); } } void D3(int u, int k) { for (int i = h[u], v; i; i = e[i].t) if ((v = e[i].v) != k) { C[v][0] = F[v][0]; for (int i = 1; f[v][i - 1]; ++i) C[v][i] = min(C[v][i - 1], C[f[v][i - 1]][i - 1]); D3(v, u); } } int main() { n = R(); m = R(); for (int i = 1; i <= n; ++i) a[F[i][0].p = F[i][1].p = i] = R(); for (int i = 1, u, v, w; i < n; ++i) u = R(), v = R(), A(u, v, w = R()), A(v, u, w); s[1] = a[1]; D1(d[1] = 1); D2(1, 0); for (int i = 1; i <= n; ++i) F[i][0].y += a[i], F[i][1].y += a[i]; C[1][0] = F[1][0]; D3(1, 0); for (int i = 0, x, y, u, v, l, k; i < m; ++i) { Q = {1000000000000000000ll, 0}; if (d[u = x = R()] < d[v = y = R()]) swap(x, y); while (d[x] > d[y]) Q = min(Q, C[x][k = __lg(d[x] - d[y])]), x = f[x][k]; if (x == y) Q = min(Q, C[l = x][0]); else { for (k = __lg(d[x]); k >= 0; --k) if (f[x][k] != f[y][k]) Q = min({Q, C[x][k], C[y][k]}), x = f[x][k], y = f[y][k]; Q = min({Q, C[x][0], C[y][0], C[l = f[x][0]][0]}); } P(Q.y + s[u] + s[v] - s[l] - s[f[l][0]]); *O++ = '\n'; } fwrite(obuf, O - obuf, 1, stdout); return 0; }
- 1
信息
- ID
- 8215
- 时间
- 1000ms
- 内存
- 512MiB
- 难度
- 5
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者