給定一棵帶權樹,定義 a[i] 為從節點 i 出發的最長路徑長度。求 a 數組中最長的連續區間,使得區間內最大值與最小值之差 ≤ m。
在數組 a[1..n] 上維護兩個單調隊列(單調遞減隊列維護最大值,單調遞增隊列維護最小值)。雙指針滑動窗口,右擴左縮,保證窗口內 `max - min ≤ m`,記錄最大窗口長度。
// 樹形 DP 部分
void dfs1(int u) {
for (auto [v, w] : G[u]) {
dfs1(v);
long long val = f[v] + w;
if (val > f[u]) { g[u] = f[u]; f[u] = val; }
else if (val > g[u]) g[u] = val;
}
}
void dfs2(int u) {
a[u] = max(f[u], h[u]);
for (auto [v, w] : G[u]) {
long long use = (f[u] == f[v] + w) ? g[u] : f[u];
use = max(use, h[u]);
h[v] = use + w;
dfs2(v);
}
}
// 單調隊列部分
int qmax[N], qmin[N], hh, tt;
for (int i = 1, j = 1; i <= n; i++) {
while (hh <= tt && a[qmax[tt]] <= a[i]) tt--;
qmax[++tt] = i;
while (hh <= tt && a[qmin[tt]] >= a[i]) tt--;
qmin[++tt] = i;
while (a[qmax[hh]] - a[qmin[hh]] > m) {
if (qmax[hh] == j) hh++;
if (qmin[hh] == j) hh++;
j++;
}
ans = max(ans, i - j + 1);
}