제출 #1252164

#제출 시각아이디문제언어결과실행 시간메모리
1252164jerry장애물 (IOI25_obstacles)C++20
24 / 100
1092 ms27064 KiB
#include <assert.h> #include <limits.h> #include <memory> #include <utility> #include <vector> class SegmentTree { public: SegmentTree(const std::vector<int>& data); int query_max(int l, int r) const; // include-exclude int get_next_le(int from, int value) const; int get_prev_gt(int from, int value) const; private: int n; std::vector<int> max, min; }; class SingleSideSolver { public: SingleSideSolver(const std::vector<int>& _t, const std::vector<int>& _h); bool can_reach(int l, int s, int d) const; private: int get_strictest_column(int l, int r) const; int get_leftmost_reachable_column(int s, int l) const; bool reduce_columns(const std::vector<int>& vals) const; const std::vector<int> t, h; const SegmentTree row_tree, col_tree; }; std::unique_ptr<SingleSideSolver> left, right; int n, m; void initialize(std::vector<int> t, std::vector<int> h) { n = t.size(); m = h.size(); left = std::make_unique<SingleSideSolver>(t, h); right = std::make_unique<SingleSideSolver>(t, std::vector<int>(h.rbegin(), h.rend())); } bool can_reach(int l, int r, int s, int d) { if (s > d) std::swap(s, d); return left->can_reach(l, s, d) && right->can_reach(m - r - 1, m - d - 1, m - s - 1); } SegmentTree::SegmentTree(const std::vector<int>& data) { n = data.size() + 1; while (__builtin_popcount(n) > 1) n += n & -n; max = std::vector<int>(n * 2, INT_MAX); min = std::vector<int>(n * 2, INT_MIN); for (int i = 0; i < data.size(); i++) max[i + n] = min[i + n] = data[i]; for (int i = n - 1; i > 0; i--) { max[i] = std::max(max[i * 2], max[i * 2 + 1]); min[i] = std::min(min[i * 2], min[i * 2 + 1]); } } int SegmentTree::query_max(int l, int r) const { int answer = INT_MIN; for (l += n, r += n; l != r; l /= 2, r /= 2) { if (l & 1) answer = std::max(answer, max[l++]); if (r & 1) answer = std::max(answer, max[--r]); } return answer; } int SegmentTree::get_next_le(int from, int value) const { from += n; while (min[from] > value) { if (from % 2 == 0) while (from % 2 == 0) from /= 2; else from++; } while (from < n) { from *= 2; if (min[from] > value) from++; } return from - n; } int SegmentTree::get_prev_gt(int from, int value) const { if (query_max(0, from + 1) <= value) return -1; from += n; while (max[from] <= value) { if (from % 2 == 1) while (from % 2 == 1) from /= 2; else from--; } while (from < n) { from *= 2; if (max[from + 1] > value) from++; } return from - n; } SingleSideSolver::SingleSideSolver(const std::vector<int>& _t, const std::vector<int>& _h) : t(_t), h(_h), row_tree(t), col_tree(h) {} bool SingleSideSolver::can_reach(int l, int s, int d) const { const int col = get_leftmost_reachable_column(s, l); const int c1 = get_strictest_column(col, s); const int c2 = get_strictest_column(col, d); return reduce_columns({h[s], c1, h[col], c2, h[d]}); } int SingleSideSolver::get_strictest_column(int l, int r) const { return col_tree.query_max(l, r + 1); } int SingleSideSolver::get_leftmost_reachable_column(int s, int l) const { int lo = l - 1, hi = s; while (lo + 1 < hi) { const int mid = (lo + hi) / 2; const int c = get_strictest_column(mid, s); if (reduce_columns({h[s], c, h[mid]})) hi = mid; else lo = mid; } return hi; } bool SingleSideSolver::reduce_columns(const std::vector<int>& vals) const { assert(t[0] > vals[0]); int max_depth = 0; for (int v : vals) { if (t[max_depth] > v) max_depth = row_tree.get_next_le(max_depth, v) - 1; else max_depth = row_tree.get_prev_gt(max_depth, v); if (max_depth < 0) return false; } return true; }
#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...