Loading

P10602 [CEOI 2009] Harbingers 题解

小清新数据结构优化 dp。

思路

考虑基本的 dp 式。

\[\begin{aligned} f_{x}&=w_{x}+\max_{i 是 x 的祖先}v_{x}\times (dep_{x}-dep_{i})+f_i\\ &=w_{x}+v_{x}\times dep_{x}+\max_{i 是 x 的祖先}-dep_{i}\times v_{x}+f_i \end{aligned}\]

发现 \(-dep_{i}\times v_{x}+f_i\) 是一次函数形式。

可以用李超树优化。

由于李超树是严格 \(O(\log n)\),所以肯定支持撤回。

我们只需要遍历一遍即可。

时间复杂度 \(O(n\log n)\)

Code

/*
  ! 如果没有天赋,那就一直重复
  ! Created: 2024/06/17 07:47:35
*/
#include <bits/stdc++.h>
using namespace std;

#define int long long
#define fro(i, x, y) for (int i = (x); i <= (y); i++)
#define pre(i, x, y) for (int i = (x); i >= (y); i--)

const int N = 1e5 + 10;
const int I = 1e9;

int n, ct, tp, tt, rt;
int w[N], v[N], f[N], dep[N], head[N];
int t[N << 5];
int ls[N << 5];
int rs[N << 5];
int*s1[N << 5];
int s2[N << 5];
struct edge {
  int to, nxt, val;
} e[N << 1];
struct line {
  int k, b;
  inline int get(int x) { return k * x + b; }
} d[N];

inline void add(int x, int y, int z) {
  e[++ct] = {y, head[x], z}, head[x] = ct;
  e[++ct] = {x, head[y], z}, head[y] = ct;
}
inline void bak(int t) {
  while (tp > t) *s1[tp] = s2[tp], tp--;
}
inline void evl(int&x, int y) {
  ++tp, s1[tp] = &x, s2[tp] = x, x = y;
}
inline void upd(int&p, int l, int r, int x) {
  if (!p) p = ++tt;
  if (!t[p]) return evl(t[p], x);
  if (l == r) return d[t[p]].get(l) > d[x].get(l) ? evl(t[p], x) : void();
  int mid = (l + r) >> 1, cur = t[p];
  if (d[t[p]].get(mid) > d[x].get(mid)) evl(t[p], x), x = cur;
  if (d[t[p]].get(l) > d[x].get(l)) upd(ls[p], l, mid, x);
  if (d[t[p]].get(r) > d[x].get(r)) upd(rs[p], mid + 1, r, x);
}
inline int ask(int p, int l, int r, int x) {
  if (!p || !t[p]) return 1e18;
  int mid = (l + r) >> 1, num = d[t[p]].get(x);
  if (mid >= x) num = min(num, ask(ls[p], l, mid, x));
  if (mid <  x) num = min(num, ask(rs[p], mid + 1, r, x));
  return num;
}
inline void dfs(int now, int fa) {
  if (now != 1) {
    f[now] = w[now] + v[now] * dep[now] + min(0ll, ask(rt, 0, I, v[now]));
    d[now] = {-dep[now], f[now]};
    upd(rt, 0, I, now);
  }
  int tim = tp;
  for (int i = head[now]; i; i = e[i].nxt) {
    if (e[i].to == fa) continue;
    dep[e[i].to] = dep[now] + e[i].val;
    dfs(e[i].to, now);
    bak(tim);
  }
}

signed main() {
  ios::sync_with_stdio(0), cin.tie(0);
  cin >> n;
  fro(i, 1, n - 1) {
    int a, b, c;
    cin >> a >> b >> c;
    add(a, b, c);
  }
  fro(i, 2, n) cin >> w[i] >> v[i];
  dfs(1, 0);
  fro(i, 2, n) cout << f[i] << " ";
  return 0;
}
posted @ 2024-06-17 14:01  JiaY19  阅读(4)  评论(0编辑  收藏  举报