[WC2010]重建计划 长链剖分 + 线段树
二分以后长链剖分 + 线段树, 扣了半天常数。
好像还用啥nb迭代优化一下二分。
#include<bits/stdc++.h> using namespace std; const int N = (int)1e5 + 7; const double eps = 1e-9; int n, L, U; int head[N], edge_tot; int len[N], son[N], w[N]; int in[N], dfs_clock; double tmp[N], add[N]; double cost; bool ok; struct Edge { int to, w, nex; } e[N << 1]; inline void addEdge(int u, int v, int w) { e[edge_tot].to = v; e[edge_tot].w = w; e[edge_tot].nex = head[u]; head[u] = edge_tot++; } #define lson l, mid, rt << 1 #define rson mid + 1, r, rt << 1 | 1 struct Tree { double mx[N << 2], lazy[N << 2]; void build(int l, int r, int rt) { lazy[rt] = 0; mx[rt] = -1e18; if(l == r) return; int mid = l + r >> 1; build(lson); build(rson); } void update2(int p, double val, int l, int r, int rt) { mx[rt] = max(mx[rt], val); if(l == r) return; int mid = l + r >> 1; if(p <= mid) update2(p, val, lson); else update2(p, val, rson); } double query(int L, int R, int l, int r, int rt) { if(R < l || r < L || R < L) return -1e18; if(L <= l && r <= R) return mx[rt]; int mid = l + r >> 1; return max(query(L, R, lson), query(L, R, rson)); } } Tree; void gao(int u, int fa) { son[u] = len[u] = 0; for(int o = head[u]; ~o; o = e[o].nex) { int v = e[o].to; if(v == fa) continue; w[v] = e[o].w; gao(v, u); if(len[v] > len[u]) { len[u] = len[v]; son[u] = v; } } len[u]++; } void dfs1(int u, int fa) { in[u] = ++dfs_clock; if(son[u]) dfs1(son[u], u); for(int o = head[u]; ~o; o = e[o].nex) { int v = e[o].to; if(v == fa || v == son[u]) continue; dfs1(v, u); } } void dfs2(int u, int fa) { if(ok) return; add[u] = 0; if(son[u]) { dfs2(son[u], u); Tree.update2(in[u], -add[son[u]] - w[son[u]] + cost, 1, n, 1); add[u] = add[son[u]] + w[son[u]] - cost; } else { Tree.update2(in[u], 0, 1, n, 1); } int l = in[u] + L; int r = min(in[u] + len[u] - 1, in[u] + U); if(Tree.query(l, r, 1, n, 1) + add[u] >= 0.0) ok = true; for(int o = head[u], v, w; ~o && !ok; o = e[o].nex) { v = e[o].to, w = e[o].w; if(v == fa || v == son[u]) continue; dfs2(v, u); for(int i = 1; i <= len[v] && i <= U && !ok; i++) { int l = max(0, L - i), r = min(len[u] - 1, U - i); tmp[in[v] + i - 1] = Tree.query(in[v] + i - 1, in[v] + i - 1, 1, n, 1) + add[v] + w - cost; if(tmp[in[v] + i - 1] + Tree.query(in[u] + l, in[u] + r, 1, n, 1) + add[u] >= 0.0) { ok = true; } } for(int i = 1; i <= len[v] && i <= U && !ok; i++) { Tree.update2(in[u] + i, tmp[in[v] + i - 1]- add[u], 1, n, 1); } } } int main() { scanf("%d%d%d", &n, &L, &U); for(int i = 1; i <= n; i++) head[i] = -1; for(int i = 1; i < n; i++) { int u, v, w; scanf("%d%d%d", &u, &v, &w); addEdge(u, v, w); addEdge(v, u, w); } gao(1, 0); dfs1(1, 0); double low = 0, high = 1000001, mid; for(int o = 0; o <= 30; o++) { mid = (low + high) / 2; cost = mid; ok = false; Tree.build(1, n, 1); dfs2(1, 0); if(ok) low = mid; else high = mid; } printf("%.3f\n", (low + high) / 2); return 0; }