제출 #1287509

#제출 시각아이디문제언어결과실행 시간메모리
1287509Ice_manRace (IOI11_race)C++17
100 / 100
312 ms80764 KiB
/** ____ ____ ____ __________________ ____ ____ ____ ||I || ||c || ||e || || || ||M || ||a || ||n || ||__|| ||__|| ||__|| ||________________|| ||__|| ||__|| ||__|| |/__\| |/__\| |/__\| |/________________\| |/__\| |/__\| |/__\| */ #include <iostream> #include <vector> #include <map> #include "race.h" #define maxn 500005 #define PB push_back #define X first #define Y second typedef long long ll; typedef std::pair<ll,ll> pll; const ll INF = (ll)4e18; std::vector<pll> v[maxn]; int n , k; ll ans; ll sumv[maxn]; int distv[maxn]; struct dsu { struct component { int par, sz; std::map<ll,ll> store; void init(int x) { par = x; sz = 1; store.clear(); } void _swap(component &other) { std::swap(sz, other.sz); store.swap(other.store); } void insert_min(ll key, ll val) { auto it = store.find(key); if(it == store.end()) store.emplace(key, val); else it->second = std::min(it->second, val); } ll get_min(ll key) const { auto it = store.find(key); if(it != store.end()) return it->second; return (ll)4e18; } // Merge 'other' into *this*: check complements against this->store, // then insert other's entries (keeping minimal depths). // target = k + 2*sum[u], depth_u is dist[u] used in candidate formula. void _merge_with(component &other, ll target, int depth_u) { // check complements (do this before mutating this->store) for (auto &pr : other.store) { ll keyB = pr.X; ll valB = pr.Y; ll need = target - keyB; auto it = store.find(need); if (it != store.end()) { ll cand = it->second + valB - 2LL * depth_u; if (cand < ans) ans = cand; } } // merge other.store into store, keeping minimal depth for (auto &pr : other.store) { ll keyB = pr.X; ll valB = pr.Y; auto it = store.find(keyB); if (it == store.end()) store.emplace(keyB, valB); else it->second = std::min(it->second, valB); } sz += other.sz; } }; std::vector<component> un; void init(int sz) { un.resize(sz + 1); for (int i = 1; i <= n; ++i) un[i].init(i); } int find_par(int node) { return node == un[node].par ? node : un[node].par = find_par(un[node].par); } }; dsu uni; // precompute prefix sums and depths, and insert (sum -> depth) into each node's component map void precomp(int u, int p, ll acc, int depth) { sumv[u] = acc; distv[u] = depth; uni.un[u].insert_min(acc, depth); for (auto &ed : v[u]) { int to = (int)ed.X; ll w = ed.Y; if (to == p) continue; precomp(to, u, acc + w, depth + 1); } } // recursion that uses small-to-large merging; uses component._merge_with to do the actual merge void small_to_large_merge(int u, int p) { ll target = (ll)k + 2LL * sumv[u]; for (auto &ed : v[u]) { int to = (int)ed.X; if (to == p) continue; small_to_large_merge(to, u); // ensure we merge smaller into larger: if child's map bigger, swap component contents if (uni.un[to].store.size() > uni.un[u].store.size()) { uni.un[to]._swap(uni.un[u]); } // now merge child's component into parent's component using component member uni.un[u]._merge_with(uni.un[to], target, distv[u]); // clear child's map to save memory uni.un[to].store.clear(); } } int best_path(int N, int K, int h[][2], int L[]) { n = N; k = K; ans = INF; // clear adjacency for (int i = 1; i <= n; ++i) v[i].clear(); for (int i = 0; i < n - 1; ++i) { int a = h[i][0] + 1; int b = h[i][1] + 1; ll w = L[i]; v[a].PB({b, w}); v[b].PB({a, w}); } uni.init(n + 5); precomp(1, 0, 0LL, 0); small_to_large_merge(1, 0); if (ans == INF) return -1; return (int)ans; }
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...