Submission #1263193

#TimeUsernameProblemLanguageResultExecution timeMemory
1263193amigoo99234Harbingers (CEOI09_harbingers)C++20
60 / 100
1098 ms33860 KiB
#include <bits/stdc++.h> using namespace std; //long long MOD = 1e9 + 7; const long long MOD = 998244353; // const long long MOD = 100000007 ; #define fast ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0) #define popCnt(x) (__builtin_popcountll(x)) #define int long long #define ld long double #define F first #define S second #define pi M_PI #define all(x) x.begin() , x.end() #define ll long long #define SZ(v) (int)(v.size()) int dx[] = {1, -1, 0, 0}; int dy[] = {0, 0, 1, -1}; const long long OO = LLONG_MAX / 4, N = 3e5 + 5, M = 1e5 + 5, K = 505; // ---------- rollback-optimized LineContainer ---------- struct Line { mutable ll k, m, p; bool operator<(const Line &o) const { return k < o.k; } bool operator<(ll x) const { return p < x; } }; struct RollbackLineContainer : multiset<Line, less<>> { static const ll inf = LLONG_MAX; bool isMn = true; // Operation types that we may need to revert enum OpType { OP_INSERT, OP_ERASE, OP_SETP }; struct Op { OpType type; Line data; // for OP_INSERT/OP_ERASE we store the full line; for OP_SETP we store old line (with old p) }; // single pool of ops for ALL adds (avoids per-add allocations) vector<Op> opsPool; // stack of indices into opsPool marking where each add started vector<size_t> addStart; RollbackLineContainer() { opsPool.reserve(1 << 20); // heuristic reserve to avoid reallocation (tweak as needed) addStart.reserve(1 << 18); } // call if you want to pre-reserve based on expected number of adds void reserve_history(size_t expected_adds, size_t avg_ops_per_add = 8) { addStart.reserve(expected_adds); opsPool.reserve(expected_adds * avg_ops_per_add); } // integer division matching original behavior (floor for negatives) ll divll(ll a, ll b) { return a / b - ((a ^ b) < 0 && a % b); } // helper: set p via mutable void set_p(iterator it, ll newp) { const_cast<ll&>(it->p) = newp; } // find a line with exact (k,m) using lower_bound (log n) iterator find_same(const Line &target) { auto it = lower_bound(target); // compares by k for (; it != end() && it->k == target.k; ++it) { if (it->m == target.m) return it; } return end(); } // log erase: push saved copy to opsPool then erase iterator erase_with_log(iterator it) { opsPool.push_back({OP_ERASE, *it}); return erase(it); } // isect with logging (stores previous p if changed), returns same boolean as before bool isect_log(iterator x, iterator y) { if (y == end()) { if (x->p != inf) opsPool.push_back({OP_SETP, *x}); set_p(x, inf); return false; } if (x->k == y->k) { ll newp = x->m > y->m ? inf : -inf; if (x->p != newp) opsPool.push_back({OP_SETP, *x}); set_p(x, newp); } else { ll newp = divll(y->m - x->m, x->k - y->k); if (x->p != newp) opsPool.push_back({OP_SETP, *x}); set_p(x, newp); } return x->p >= y->p; } // add a line, logging minimal info into the single opsPool void add(ll k, ll m) { size_t startIndex = opsPool.size(); // mark where this add's ops start addStart.push_back(startIndex); if (isMn) { k = -k; m = -m; } auto z = insert({k, m, 0}); opsPool.push_back({OP_INSERT, *z}); // remember insertion so rollback removes it auto y = z++; auto x = y; while (isect_log(y, z)) { z = erase_with_log(z); } if (x != begin() && isect_log(--x, y)) { // erase y (logged) and re-evaluate y = erase_with_log(y); isect_log(x, y); } while ((y = x) != begin()) { --x; if (x->p >= y->p) { // erase y (logged) and update x's p (logged in isect_log) auto nxt = erase_with_log(y); isect_log(x, nxt); } else break; } } // query unchanged ll query(ll x) { auto l = *lower_bound(x); return (isMn ? -1 : 1) * (l.k * x + l.m); } // rollback the last add (undo in reverse order) void rollback() { if (addStart.empty()) return; size_t start = addStart.back(); addStart.pop_back(); // revert ops in reverse order for (size_t idx = opsPool.size(); idx-- > start; ) { Op &op = opsPool[idx]; if (op.type == OP_ERASE) { // inverse of erase: re-insert the stored copy insert(op.data); } else if (op.type == OP_SETP) { // inverse of set-p: find the line with same (k,m) and restore its p auto it = find_same(op.data); if (it != end()) set_p(it, op.data.p); } else if (op.type == OP_INSERT) { // inverse of insert: find the inserted line and erase it auto it = find_same(op.data); if (it != end()) erase(it); } } // shrink opsPool back to 'start' opsPool.resize(start); } // rollback last t adds (safe if t > history size) void rollback_n(size_t t) { while (t-- && !addStart.empty()) rollback(); } // clear history to free memory of the opsPool void clear_history() { opsPool.clear(); addStart.clear(); } }; RollbackLineContainer cht; int n; vector<int> v, c; vector<vector<pair<int, int>>> adj; vector<int> dp; void dfs(int node , int p = -1 , int d = 0) { if(p == -1) dp[node] = 0; else dp[node] = cht.query(v[node]) + v[node] * d + c[node]; cht.add(-d , dp[node]); for(auto [child , len] : adj[node]) { if(child == p)continue; dfs(child , node , d + len); } cht.rollback(); } signed main() { fast; // freopen("in.txt", "r", stdin); // freopen("out.txt", "w", stdout); cin >> n; dp = v = c = vector<int>(n); adj.resize(n); for (int i = 0; i < n - 1; ++i) { int u, vv, d; cin >> u >> vv >> d; u--; vv--; adj[u].emplace_back(vv, d); adj[vv].emplace_back(u, d); } for (int i = 1; i < n; ++i) { cin >> c[i] >> v[i]; } dfs(0); for(int i = 1 ; i < n ; i++) cout << dp[i] << " "; cout<<'\n'; }
#Verdict Execution timeMemoryGrader output
Fetching results...