[WC2010]重建计划

给定一颗带边权的树,求一条边数在 \([L, R]\) 之间的路径,并使得路径上边权的平均值最大。输出这个最大平均值。

\(n \leq 10^5\)。

同中位数 [Codeforces150E] Freezing with Style

二分答案 \(ans\),每个边权减去 \(ans\),转换为判断是否存在路径的边权和非负。

这里是长链剖分的解法,点分治的见上一篇。

#include <bits/stdc++.h>
#define dbg(...) std::cerr << "\033[32;1m", fprintf(stderr, __VA_ARGS__), std::cerr << "\033[0m"
template <class T, class U>
inline bool smin(T &x, const U &y) { return y < x ? x = y, 1 : 0; }
template <class T, class U>
inline bool smax(T &x, const U &y) { return x < y ? x = y, 1 : 0; }
using LL = long long;
using PII = std::pair<int, int>;

constexpr int N(1e5 + 5);
constexpr double EPS(1e-6);
int n, l_, r_;
int fa[N], f[N], son[N], val[N];
std::vector<PII> g[N];
void dfs1(int x) {
  for (auto [y, z] : g[x]) {
    if (y == fa[x]) {
      continue;
    }
    fa[y] = x;
    dfs1(y);
    if (smax(f[x], f[y] + 1)) {
      son[x] = y;
      val[x] = z;
    }
  }
}
struct Node {
  Node *ls, *rs;
  double max, add;
  void pushdown() {
    if (add) {
      if (ls) ls->add += add, ls->max += add;
      if (rs) rs->add += add, rs->max += add;
      add = 0;
    }
  }
  void pushup() {
    assert(rs);
    max = ls ? std::max(ls->max, rs->max) : rs->max;
  }
} t[N << 2], *ptr;
void ins(Node *&o, int l, int r, int x, double y) {
  if (!o) {
    o = ptr++;
    o->ls = o->rs = nullptr;
    o->max = -1e9;
  }
  o->pushdown();
  smax(o->max, y);
  if (l == r) {
    return;
  }
  int m = l + r >> 1;
  x <= m ? ins(o->ls, l, m, x, y) : ins(o->rs, m + 1, r, x, y);
}
void update(Node *o, int l, int r, int x, int y, double z) {
  if (!o) return;
  if (x <= l && r <= y) {
    o->add += z;
    o->max += z;
    return;
  }
  // assert(l < r);
  o->pushdown();
  int m = l + r >> 1;
  if (x <= m) update(o->ls, l, m, x, y, z);
  if (y > m) update(o->rs, m + 1, r, x, y, z);
  o->pushup();
}
double ask(Node *o, int l, int r, int x, int y) {
  if (!o || x > r || y < l) {
    return -1e9;
  }
  if (x <= l && r <= y) {
    return o->max;
  }
  o->pushdown();
  int m = l + r >> 1;
  return std::max(ask(o->ls, l, m, x, y), ask(o->rs, m + 1, r, x, y));
}
Node *root[N];
double average;
bool dfs2(int x, int dep) {
  root[x] = nullptr;
  if (son[x]) {
    if (dfs2(son[x], dep + 1)) return true;
    root[x] = root[son[x]];
    update(root[x], 0, dep + f[x], dep + 1, dep + f[x], val[x] - average);
  }
  ins(root[x], 0, dep + f[x], dep, 0);
  if (ask(root[x], 0, dep + f[x], dep + l_, dep + r_) > EPS) {
    return true;
  }
  for (auto [y, z] : g[x]) {
    if (y == fa[x] || y == son[x]) {
      continue;
    }
    if (dfs2(y, 0)) return true;
    static double d[N];
    std::function<void(Node*, int l, int r)> dfs = [&](Node *o, int l, int r) {
      assert(o);
      if (l == r) {
        d[l] = o->max;
        return;
      }
      o->pushdown();
      int m = l + r >> 1;
      dfs(o->ls, l, m), dfs(o->rs, m + 1, r);
    };
    dfs(root[y], 0, f[y]);
    for (int i = 0; i <= f[y]; i++) {
      if (d[i] + z - average + ask(root[x], 0, dep + f[x], dep + l_ - i - 1, dep + r_ - i - 1) > EPS) {
        return true;
      }
    }
    for (int i = 0; i <= f[y]; i++) {
      ins(root[x], 0, dep + f[x], dep + i + 1, d[i] + z - average);
    }
  }
  return false;
}
int main() {
  std::ios::sync_with_stdio(false);
  std::cin.tie(nullptr);
  std::cin >> n >> l_ >> r_;
  double l = 0, r = 0;
  for (int i = 1, x, y, z; i < n; i++) {
    std::cin >> x >> y >> z;
    g[x].emplace_back(y, z);
    g[y].emplace_back(x, z);
    smax(r, z);
  }
  dfs1(1);
  while (r - l > EPS) {
    average = (l + r) / 2;
    ptr = t;
    if (dfs2(1, 0)) {
      l = average;
    } else {
      r = average;
    }
  }
  printf("%.3f", l);
  return 0;
}
上一篇:P4293 [WC2010]能量场


下一篇:[WC2010]重建计划 长链剖分 + 线段树