Submission #607086

#TimeUsernameProblemLanguageResultExecution timeMemory
607086TemmieComparing Plants (IOI20_plants)C++17
0 / 100
1 ms424 KiB
#include <bits/stdc++.h> struct Seg { int size; std::vector <int> lazy, min; Seg(const std::vector <int> a) { size = 1; while (size < (int) a.size()) { size <<= 1; } lazy.resize(size << 1, 0); min.resize(size << 1, 1 << 30); build(a); } inline void push(int now, int l, int r) { min[now] += lazy[now]; if (r - l - 1) { lazy[now * 2 + 1] += lazy[now]; lazy[now * 2 + 2] += lazy[now]; } lazy[now] = 0; } inline void build(const std::vector <int>& a) { build(a, 0, 0, a.size()); } void build(const std::vector <int>& a, int now, int l, int r) { if (!(r - l - 1)) { min[now] = a[l]; return; } int mid = (l + r) >> 1; build(a, now * 2 + 1, l, mid); build(a, now * 2 + 2, mid, r); min[now] = std::min(min[now * 2 + 1], min[now * 2 + 2]); } inline void update(int l, int r, int val) { update(l, r, val, 0, 0, size); } void update(int tl, int tr, int val, int now, int l, int r) { if (l >= tr || r <= tl) { return; } if (l >= tl && r <= tr) { lazy[now] += val; push(now, l, r); return; } int mid = (l + r) >> 1; push(now, l, r); update(tl, tr, val, now * 2 + 1, l, mid); update(tl, tr, val, now * 2 + 2, mid, r); min[now] = std::min(min[now * 2 + 1], min[now * 2 + 2]); } inline int find_last_zero(int l, int r) { if (l == r) { return -1; } return find_last_zero(l, r, 0, 0, size); } int find_last_zero(int tl, int tr, int now, int l, int r) { if (l >= tr || r <= tl) { return -1; } push(now, l, r); if (min[now]) { return -1; } if (!(r - l - 1)) { return l; } int mid = (l + r) >> 1; int right = find_last_zero(tl, tr, now * 2 + 2, mid, r); return right == -1 ? find_last_zero(tl, tr, now * 2 + 1, l, mid) : right; } inline int find_first_zero(int l, int r) { if (l == r) { return -1; } return find_first_zero(l, r, 0, 0, size); } int find_first_zero(int tl, int tr, int now, int l, int r) { if (l >= tr || r <= tl) { return -1; } push(now, l, r); if (min[now]) { return -1; } if (!(r - l - 1)) { return l; } int mid = (l + r) >> 1; int left = find_first_zero(tl, tr, now * 2 + 1, l, mid); return left == -1 ? find_first_zero(tl, tr, now * 2 + 2, mid, r) : left; } inline int query(int ind) { return query(ind, 0, 0, size); } int query(int ind, int now, int l, int r) { push(now, l, r); if (!(r - l - 1)) { return min[now]; } int mid = (l + r) >> 1; return ind < mid ? query(ind, now * 2 + 1, l, mid) : query(ind, now * 2 + 2, mid, r); } inline int query(int l, int r) { return query(l, r, 0, 0, size); } int query(int tl, int tr, int now, int l, int r) { if (l >= tr || r <= tl) { return 1 << 30; } push(now, l, r); if (l >= tl && r <= tr) { return min[now]; } int mid = (l + r) >> 1; return std::min(query(tl, tr, now * 2 + 1, l, mid), query(tl, tr, now * 2 + 2, mid, r)); } inline void set(int ind, int val) { set(ind, val, 0, 0, size); } void set(int ind, int val, int now, int l, int r) { if (!(r - l - 1)) { lazy[now] = 0; min[now] = val; return; } int mid = (l + r) >> 1; push(now, l, r); ind < mid ? set(ind, val, now * 2 + 1, l, mid) : set(ind, val, now * 2 + 2, mid, r); push(now * 2 + 1, l, mid); push(now * 2 + 2, mid, r); min[now] = std::min(min[now * 2 + 1], min[now * 2 + 2]); } }; int n, k; std::vector <int> h; std::vector <std::vector <int>> bin_left, bin_right; void init(int _k, std::vector <int> r) { n = r.size(); k = _k; h.resize(n, -1); Seg seg(r); std::vector <int> ord; auto f = [&] (auto&& self, int node) -> void { int ind = -1; do { ind = -1; if (node - k + 1 >= 0) { ind = seg.find_last_zero(node - k + 1, node); } else { ind = seg.find_last_zero(0, node); if (ind == -1) { ind = seg.find_first_zero(n - ((k - 1) - node), n); } } if (ind != -1) { self(self, ind); } } while (ind != -1); if (node - k + 1 >= 0) { seg.update(node - k + 1, node + 1, -1); } else { seg.update(0, node + 1, -1); seg.update(n - ((k - 1) - node), n, -1); } seg.update(node, node + 1, 1 << 30); ord.push_back(node); }; while (true) { int v = seg.find_first_zero(0, n); if (v == -1) { break; } f(f, v); } assert((int) ord.size() == n); for (int i = 0; i < n; i++) { h[ord[i]] = n - i - 1; } std::vector <int> left(n, -1), right(n - 1); Seg fseg(std::vector <int> (n, 1 << 30)); for (int i = n - 1; i >= 0; i--) { int node = ord[i]; if (node - k + 1 >= 0) { int val = fseg.query(node - k + 1, node); left[node] = val < (1 << 30) ? ord[val] : -1; } else { int val = std::min(fseg.query(0, node), fseg.query(n - ((k - 1) - node), n)); left[node] = val < (1 << 30) ? ord[val] : -1; } if (node + k - 1 < n) { int val = fseg.query(node + 1, node + k); right[node] = val < (1 << 30) ? ord[val] : -1; } else { int val = std::min(fseg.query(node + 1, n), fseg.query(0, (k - 1) - (n - node - 1))); right[node] = val < (1 << 30) ? ord[val] : -1; } fseg.set(node, i); } bin_left.resize(20, std::vector <int> (n, -1)); bin_right.resize(20, std::vector <int> (n, -1)); bin_left[0] = left; bin_right[0] = right; for (int b = 1; b < 20; b++) { for (int i = 0; i < n; i++) { bin_left[b][i] = bin_left[b - 1][i] == -1 ? -1 : bin_left[b - 1][bin_left[b - 1][i]]; bin_right[b][i] = bin_right[b - 1][i] == -1 ? -1 : bin_right[b - 1][bin_right[b - 1][i]]; } } } inline bool contains(int from, int to, int target) { if (from <= to) { return from <= target && target <= to; } return contains(from, n - 1, target) || contains(0, to, target); } inline int dist(int from, int to) { if (from <= to) { return to - from; } return to + 1 + (n - from - 1); } bool greater(int u, int v) { { int ind = u; int d = dist(v, u) - 1; for (int b = 19; b >= 0; b--) { if (bin_left[b][ind] != -1 && d - dist(bin_left[b][ind], ind) >= 0) { ind = bin_left[b][ind]; d -= dist(bin_left[b][ind], ind); } } int v1 = ind; int v2 = bin_left[0][ind]; if (v2 != -1 && contains(v2, v1, v) && h[v1] > h[v]) { return true; } } { int ind = u; int d = dist(u, v) - 1; for (int b = 19; b >= 0; b--) { if (bin_right[b][ind] != -1 && d - dist(ind, bin_right[b][ind]) >= 0) { ind = bin_right[b][ind]; d -= dist(ind, bin_right[b][ind]); } } int v1 = ind; int v2 = bin_right[0][ind]; if (v2 != -1 && contains(v1, v2, v) && h[v1] > h[v]) { return true; } } return false; } int compare_plants(int u, int v) { if (greater(u, v)) { return 1; } if (greater(v, u)) { return -1; } return 0; }
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...