给定一颗带边权的树,求一条边数在 \([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;
}