Submission #1263367

#TimeUsernameProblemLanguageResultExecution timeMemory
1263367amigoo99234Harbingers (CEOI09_harbingers)C++20
80 / 100
129 ms66148 KiB
#include <bits/stdc++.h> using namespace std; using ll = long long; const ll INFLL = (1LL<<62); // ---------- Li Chao on a fixed set of x-coordinates (segment-style) ---------- // Lines: y = m*x + b struct Line { ll m, b; Line(ll _m = 0, ll _b = INFLL) : m(_m), b(_b) {} inline ll eval_ll(ll x) const { __int128 v = ( __int128 )m * x + b; if (v > INFLL) return INFLL; if (v < -INFLL) return -INFLL; return (ll)v; } }; // segment tree holds a line on each node, node range corresponds to discrete x indices [L..R] // xs[] holds the real x coordinate for each index. struct LiChaoSeg { int M; // number of distinct x values vector<Line> seg; // size 4*M vector<ll> xs; // sorted distinct x coordinates // change record for rollback: node index + previous line struct Change { int node; Line old; }; vector<Change> changes; vector<int> checkpoints; LiChaoSeg() : M(0) {} void init_from_xs(vector<ll> &coords) { xs = coords; sort(xs.begin(), xs.end()); xs.erase(unique(xs.begin(), xs.end()), xs.end()); M = (int)xs.size(); seg.assign(4 * max(1, M), Line()); changes.clear(); checkpoints.clear(); } // insert tracked: push checkpoint, then call insert_impl void insert_tracked(Line newline) { checkpoints.push_back((int)changes.size()); if (M > 0) insert_impl(1, 0, M - 1, newline); } void rollback_last_insert() { if (checkpoints.empty()) return; int target = checkpoints.back(); checkpoints.pop_back(); while ((int)changes.size() > target) { Change ch = changes.back(); changes.pop_back(); seg[ch.node] = ch.old; } } // record change of seg[node] inline void record_node(int node) { changes.push_back({node, seg[node]}); } // insertion on indices interval [l,r] void insert_impl(int node, int l, int r, Line newline) { int mid = (l + r) >> 1; ll xl = xs[l], xm = xs[mid], xr = xs[r]; Line cur = seg[node]; // compare at mid value bool leftBetter = newline.eval_ll(xl) < cur.eval_ll(xl); bool midBetter = newline.eval_ll(xm) < cur.eval_ll(xm); if (midBetter) { // overwrite node's line (record old) record_node(node); swap(seg[node], newline); // now newline holds old seg[node] cur = seg[node]; // updated } if (l == r) return; if (leftBetter != midBetter) { // affects left child insert_impl(node<<1, l, mid, newline); } else { // affects right child insert_impl(node<<1|1, mid+1, r, newline); } } // query value at actual x (which must exist in xs) ll query_at_x(ll x) const { if (M == 0) return INFLL; int idx = lower_bound(xs.begin(), xs.end(), x) - xs.begin(); // assume x is present in xs return query_impl(1, 0, M - 1, idx, x); } ll query_impl(int node, int l, int r, int idx, ll x) const { ll res = seg[node].eval_ll(x); if (l == r) return res; int mid = (l + r) >> 1; if (idx <= mid) return min(res, query_impl(node<<1, l, mid, idx, x)); else return min(res, query_impl(node<<1|1, mid+1, r, idx, x)); } }; // ---------------- Problem-specific code (Harbingers COI 2009) ---------------- int main() { ios::sync_with_stdio(false); cin.tie(nullptr); #if defined(__GNUC__) // optional: increase recursion depth if needed #endif int N; if (!(cin >> N)) return 0; vector<vector<pair<int,int>>> adj(N); for (int i = 0; i < N-1; ++i) { int u,v,d; cin >> u >> v >> d; --u; --v; adj[u].push_back({v,d}); adj[v].push_back({u,d}); } // S and V for nodes 2..N (input gives N-1 pairs) vector<ll> S(N, 0), V(N, 0); for (int i = 1; i < N; ++i) { cin >> S[i] >> V[i]; } // compute dist from root (node 0) vector<ll> dist(N, 0); // we will also need parent order for DFS vector<int> parent(N, -1), order; order.reserve(N); // iterative stack to avoid recursion limit when computing distances { order.push_back(0); parent[0] = -2; // mark root visited for (size_t i = 0; i < order.size(); ++i) { int u = order[i]; for (auto [v, w] : adj[u]) if (parent[v] == -1) { parent[v] = u; dist[v] = dist[u] + w; order.push_back(v); } } } // prepare xs = distinct V[i] (only nodes 1..N-1 have V) vector<ll> xs; xs.reserve(N); for (int i = 1; i < N; ++i) xs.push_back(V[i]); sort(xs.begin(), xs.end()); xs.erase(unique(xs.begin(), xs.end()), xs.end()); LiChaoSeg lich; lich.init_from_xs(xs); // We'll perform a DFS from root and maintain Li Chao with rollback: // - at entering node u: if u==0 (root) dp[0]=0 and we insert line for root: slope = -dist[0]=0, intercept = dp[0]=0 // - for other u: dp[u] = query(V[u]) + dist[u]*V[u] + S[u]; then insert line with slope = -dist[u], intercept = dp[u] // After processing children, rollback last insert. vector<ll> dp(N, 0); // iterative DFS with manual stack to manage rollback points and visiting order (enter/exit) struct Frame { int u; int p; int it; bool entered; }; vector<Frame> stack; stack.push_back({0, -1, 0, false}); while (!stack.empty()) { Frame f = stack.back(); stack.pop_back(); int u = f.u, p = f.p; if (!f.entered) { // ENTRY // compute dp if (u == 0) { dp[u] = 0; } else { ll best = lich.query_at_x(V[u]); // if lich gave INF (tree empty), best will be INF -> dp huge; but root line exists from root insertion dp[u] = best; if (dp[u] >= INFLL/4) dp[u] = INFLL; // safe else { dp[u] = dp[u] + dist[u] * V[u] + S[u]; } } // push EXIT frame stack.push_back({u, p, 0, true}); // insert this node's line into Li Chao // line: y(x) = (-dist[u])*x + dp[u] Line L(-dist[u], dp[u]); lich.insert_tracked(L); // push children (enter frames) onto stack for (auto &ed : adj[u]) { int v = ed.first; if (v == p) continue; stack.push_back({v, u, 0, false}); } } else { // EXIT: rollback the insertion we did on ENTRY for this node lich.rollback_last_insert(); } } // print dp[1..N-1] for (int i = 1; i < N; ++i) { cout << dp[i] << (i+1 < N ? ' ' : '\n'); } return 0; }
#Verdict Execution timeMemoryGrader output
Fetching results...