제출 #1290583

#제출 시각아이디문제언어결과실행 시간메모리
1290583nonadhocproblemsGift Exchange (JOI24_ho_t4)C++20
100 / 100
1087 ms99640 KiB
#include <bit> #include <bitset> #include <iostream> #include <iomanip> #include <string> #include <sstream> #include <cstdio> #include <vector> #include <array> #include <deque> #include <queue> #include <stack> #include <set> #include <map> #include <unordered_set> #include <unordered_map> #include <algorithm> #include <numeric> #include <iterator> #include <utility> #include <tuple> #include <cstdint> #include <limits> #include <type_traits> #include <cmath> #include <complex> #include <random> #include <chrono> #include <cstring> #include <cctype> #include <cassert> #include <cstdlib> using namespace std; #ifdef natural_selection #include "../../../libra/misc/dbg.h" #else #define debug(...) #define endl "\n" #endif const int inf = 1e9; namespace seg_tree { // Floor of log_2(a); index of highest 1-bit inline int floor_log_2(int a) { return a ? bit_width(unsigned(a)) - 1 : -1; } class point { public: int a; point() : a(0) {} explicit point(int a_) : a(a_) { assert(a >= -1); } explicit operator bool() { return bool(a); } // This is useful so you can directly do array indices /* implicit */ operator int() const { return a; } point c(bool z) const { return point((a << 1) | z); } point operator[](bool z) const { return c(z); } point p() const { return point(a >> 1); } friend std::ostream &operator<<(std::ostream &o, const point &p) { return o << int(p); } template <typename F> void for_each(F f) const { for (int v = a; v > 0; v >>= 1) { f(point(v)); } } template <typename F> void for_parents_down(F f) const { // strictly greater than 0 for (int L = floor_log_2(a); L > 0; L--) { f(point(a >> L)); } } template <typename F> void for_parents_up(F f) const { for (int v = a >> 1; v > 0; v >>= 1) { f(point(v)); } } point &operator++() { ++a; return *this; } point operator++(int) { return point(a++); } point &operator--() { --a; return *this; } point operator--(int) { return point(a--); } }; class range { public: int a, b; range() : a(1), b(1) {} range(int a_, int b_) : a(a_), b(b_) { assert(1 <= a && a <= b && b <= 2 * a); } explicit range(std::array<int, 2> r) : range(r[0], r[1]) {} explicit operator std::array<int, 2>() const { return {a, b}; } const int &operator[](bool z) const { return z ? b : a; } friend std::ostream &operator<<(std::ostream &o, const range &r) { return o << "[" << r.a << ".." << r.b << ")"; } // Iterate over the range from outside-in. // Calls f(point a) template <typename F> void for_each(F f) const { for (int x = a, y = b; x < y; x >>= 1, y >>= 1) { if (x & 1) f(point(x++)); if (y & 1) f(point(--y)); } } // Iterate over the range from outside-in. // Calls f(point a, bool is_right) template <typename F> void for_each_with_side(F f) const { for (int x = a, y = b; x < y; x >>= 1, y >>= 1) { if (x & 1) f(point(x++), false); if (y & 1) f(point(--y), true); } } // Iterate over the range from left to right. // Calls f(point) template <typename F> void for_each_l_to_r(F f) const { int anc_depth = floor_log_2((a - 1) ^ b); int anc_msk = (1 << anc_depth) - 1; for (int v = (-a) & anc_msk; v; v &= v - 1) { int i = countr_zero(unsigned(v)); f(point(((a - 1) >> i) + 1)); } for (int v = b & anc_msk; v;) { int i = floor_log_2(v); f(point((b >> i) - 1)); v ^= (1 << i); } } // Iterate over the range from right to left. // Calls f(point) template <typename F> void for_each_r_to_l(F f) const { int anc_depth = floor_log_2((a - 1) ^ b); int anc_msk = (1 << anc_depth) - 1; for (int v = b & anc_msk; v; v &= v - 1) { int i = countr_zero(unsigned(v)); f(point((b >> i) - 1)); } for (int v = (-a) & anc_msk; v;) { int i = floor_log_2(v); f(point(((a - 1) >> i) + 1)); v ^= (1 << i); } } template <typename F> void for_parents_down(F f) const { int x = a, y = b; if ((x ^ y) > x) { x <<= 1, std::swap(x, y); } int dx = countr_zero(unsigned(x)); int dy = countr_zero(unsigned(y)); int anc_depth = floor_log_2((x - 1) ^ y); for (int i = floor_log_2(x); i > dx; i--) { f(point(x >> i)); } for (int i = anc_depth; i > dy; i--) { f(point(y >> i)); } } template <typename F> void for_parents_up(F f) const { int x = a, y = b; if ((x ^ y) > x) { x <<= 1, std::swap(x, y); } int dx = countr_zero(unsigned(x)); int dy = countr_zero(unsigned(y)); int anc_depth = floor_log_2((x - 1) ^ y); for (int i = dx + 1; i <= anc_depth; i++) { f(point(x >> i)); } for (int v = y >> (dy + 1); v; v >>= 1) { f(point(v)); } } }; class in_order_layout { public: // Alias them in for convenience using point = seg_tree::point; using range = seg_tree::range; int n, s; in_order_layout() : n(0), s(0) {} in_order_layout(int n_) : n(n_), s(n ? bit_ceil(unsigned(n)) : 0) {} point get_point(int a) const { assert(0 <= a && a < n); a += s; return point(a >= 2 * n ? a - n : a); } range get_range(int a, int b) const { assert(0 <= a && a <= b && b <= n); if (n == 0) return range(); a += s, b += s; return range((a >= 2 * n ? 2 * (a - n) : a), (b >= 2 * n ? 2 * (b - n) : b)); } range get_range(std::array<int, 2> p) const { return get_range(p[0], p[1]); } int get_leaf_index(point pt) const { int a = int(pt); assert(n <= a && a < 2 * n); return (a < s ? a + n : a) - s; } std::array<int, 2> get_node_bounds(point pt) const { int a = int(pt); assert(1 <= a && a < 2 * n); int l = countl_zero(unsigned(a)) - countl_zero(unsigned(2 * n - 1)); int x = a << l, y = (a + 1) << l; assert(s <= x && x < y && y <= 2 * s); return {(x >= 2 * n ? (x >> 1) + n : x) - s, (y >= 2 * n ? (y >> 1) + n : y) - s}; } int get_node_split(point pt) const { int a = int(pt); assert(1 <= a && a < n); int l = countl_zero(unsigned(2 * a + 1)) - countl_zero(unsigned(2 * n - 1)); int x = (2 * a + 1) << l; assert(s <= x && x < 2 * s); return (x >= 2 * n ? (x >> 1) + n : x) - s; } int get_node_size(point pt) const { auto bounds = get_node_bounds(pt); return bounds[1] - bounds[0]; } }; class circular_layout { public: // Alias them in for convenience using point = seg_tree::point; using range = seg_tree::range; int n; circular_layout() : n(0) {} circular_layout(int n_) : n(n_) {} point get_point(int a) const { assert(0 <= a && a < n); return point(n + a); } range get_range(int a, int b) const { assert(0 <= a && a <= b && b <= n); if (n == 0) return range(); return range(n + a, n + b); } range get_range(std::array<int, 2> p) const { return get_range(p[0], p[1]); } int get_leaf_index(point pt) const { int a = int(pt); assert(n <= a && a < 2 * n); return a - n; } // Returns {x,y} so that 0 <= x < n and 1 <= y <= n // If the point is non-wrapping, then 0 <= x < y <= n std::array<int, 2> get_node_bounds(point pt) const { int a = int(pt); assert(1 <= a && a < 2 * n); int l = countl_zero(unsigned(a)) - countl_zero(unsigned(2 * n - 1)); int s = bit_ceil(unsigned(n)); int x = a << l, y = (a + 1) << l; assert(s <= x && x < y && y <= 2 * s); return {(x >= 2 * n ? x >> 1 : x) - n, (y > 2 * n ? y >> 1 : y) - n}; } // Returns the split point of the node, such that 1 <= s <= n. int get_node_split(point pt) const { int a = int(pt); assert(1 <= a && a < n); return get_node_bounds(pt.c(0))[1]; } int get_node_size(point pt) const { auto bounds = get_node_bounds(pt); int r = bounds[1] - bounds[0]; return r > 0 ? r : r + n; } }; } template <typename info, typename tag> class f_lazy_segment_tree_chan { public: int n; vector<info> infos; vector<tag> tags; seg_tree::in_order_layout layout; void apply(seg_tree::point a, const tag &t) { auto [l, r] = layout.get_node_bounds(a); if (!t.apply_to(infos[a], l, r - 1)) //r - 1 to make inclusive { assert(a < n); downdate_node(a); apply(a.c(0), t); apply(a.c(1), t); update_node(a); return; } if (a < n) { t.apply_to(tags[a]); } } void downdate_node(seg_tree::point a) { if (!tags[a].empty()) { apply(a.c(0), tags[a]); apply(a.c(1), tags[a]); tags[a] = tag(); } } void update_node(seg_tree::point a) { infos[a] = infos[a.c(0)].unite(infos[a.c(1)]); } f_lazy_segment_tree_chan() : f_lazy_segment_tree_chan(0) {} f_lazy_segment_tree_chan(int n_) : f_lazy_segment_tree_chan(vector<info>(n_)) {} f_lazy_segment_tree_chan(const vector<info> &a) : n(int(a.size())) { infos.resize(2 * n); tags.resize(n); layout = seg_tree::in_order_layout(n); for (int i = 0; i < n; i++) { infos[layout.get_point(i)] = a[i]; } for (int i = n - 1; i >= 1; i--) { update_node(seg_tree::point(i)); } } void modify(int l, int r, const tag &t) { ++ r; auto rng = layout.get_range(l, r); rng.for_parents_down([&](seg_tree::point a) { downdate_node(a); }); rng.for_each([&](seg_tree::point a) { apply(a, t); }); rng.for_parents_up([&](seg_tree::point a) { update_node(a); }); } void set(int p, const info &v) { auto pt = layout.get_point(p); pt.for_parents_down([&](seg_tree::point a) { downdate_node(a); }); infos[pt] = v; pt.for_parents_up([&](seg_tree::point a) { update_node(a); }); } info query(int l, int r) { ++ r; auto rng = layout.get_range(l, r); rng.for_parents_down([&](seg_tree::point a) { downdate_node(a); }); info res; rng.for_each_l_to_r([&](seg_tree::point a) { res = res.unite(infos[a]); }); return res; } info get(int p) { auto pt = layout.get_point(p); pt.for_parents_down([&](seg_tree::point a) { downdate_node(a); }); return infos[pt]; } //returns max point r such that f(sum[l, r]) = true given that f is monotonic as r increases //if (r > n), then f(sum[l, n]) = true //if (r < l), then f(sum[l, l]) = false template <typename F> int max_right(int l, F f) { auto rng = layout.get_range(l, n); rng.for_parents_down([&](seg_tree::point a) { downdate_node(a); }); int res = n; info sum; rng.for_each_l_to_r([&](seg_tree::point a) { if (res != n) { return; } auto new_sum = sum.unite(infos[a]); if (f(new_sum)) { sum = new_sum; return; } while (a < n) { downdate_node(a); new_sum = sum.unite(infos[a.c(0)]); if (f(new_sum)) { sum = new_sum; a = a.c(1); } else { a = a.c(0); } } res = layout.get_node_bounds(a)[0]; }); -- res; return min(res, n); } //returns min point l such that f(sum[l, r]) = true given that f is monotonic as l decreases //if (l == 0), then f(sum[0, n]) = true //if (l > r), then f(sum[r, r]) = false template <typename F> int min_left(int r, F f) { ++ r; auto rng = layout.get_range(0, r); rng.for_parents_down([&](seg_tree::point a) { downdate_node(a); }); int res = 0; info sum; rng.for_each_r_to_l([&](seg_tree::point a) { if (res != 0) { return; } auto new_sum = infos[a].unite(sum); if (f(new_sum)) { sum = new_sum; return; } while (a < n) { downdate_node(a); new_sum = infos[a.c(1)].unite(sum); if (f(new_sum)) { sum = new_sum; a = a.c(0); } else { a = a.c(1); } } res = layout.get_node_bounds(a)[1]; }); return res; } }; class monoid_chan { public: int mx = -inf, mn = inf; monoid_chan() : mx(-inf), mn(inf) {}; monoid_chan(int x) : mx(x), mn(x) {}; monoid_chan unite(monoid_chan b) const { monoid_chan res; res.mx = max(mx, b.mx); res.mn = min(mn, b.mn); return res; } static monoid_chan get_default([[maybe_unused]] int l, [[maybe_unused]] int r) { return monoid_chan(); } }; class tag_chan { public: int app = -1; tag_chan() : app(-1) {}; tag_chan(int x) : app(x) {}; bool apply_to(monoid_chan &a, [[maybe_unused]] int l, [[maybe_unused]] int r) const { assert(app != -1); a.mn = a.mx = app; return true; } void apply_to(tag_chan &t) const { t.app = app; } bool empty() const { return app == -1; } }; class monoid_chan2 { public: int val; monoid_chan2() : val(0) {}; monoid_chan2(int x) : val(x) {}; monoid_chan2 unite(monoid_chan2 b) const { monoid_chan2 res(val + b.val); return res; } static monoid_chan2 get_default([[maybe_unused]] int l, [[maybe_unused]] int r) { return monoid_chan2(); } }; class tag_chan2 { public: int add = 0; tag_chan2() : add(0) {}; tag_chan2(int x) : add(x) {}; bool apply_to(monoid_chan2 &a, [[maybe_unused]] int l, [[maybe_unused]] int r) const { a.val += add; return true; } void apply_to(tag_chan2 &t) const { t.add += add; } bool empty() const { return add == 0; } }; /* class monoid_chan3 { public: int sum = 0; monoid_chan3() : sum(0) {}; monoid_chan3(int x) : sum(x) {}; monoid_chan3 unite(monoid_chan3 b) const { monoid_chan3 res(sum + b.sum); return res; } static monoid_chan3 get_default([[maybe_unused]] int l, [[maybe_unused]] int r) { return monoid_chan3(); } }; class tag_chan3 { public: int add = 0; tag_chan3() : add(0) {}; tag_chan3(int x) : add(x) {}; bool apply_to(monoid_chan3 &a, [[maybe_unused]] int l, [[maybe_unused]] int r) const { a.sum += add * (r - l + 1); return true; } void apply_to(tag_chan3 &t) const { t.add += add; } bool empty() const { return add == 0; } }; */ signed main() { ios_base::sync_with_stdio(false), cin.tie(NULL); int t = 1; // cin >> t; while(t --) { int n; cin >> n; vector<int> a(n + 1); for(int i = 1; i <= n; i ++) cin >> a[i]; vector<int> b(n + 1); for(int i = 1; i <= n; i ++) cin >> b[i]; int q; cin >> q; vector<pair<int, int>> qr(q); vector<vector<pair<int, int>>> store(n + 1); for(int i = 0; i < q; i ++) { auto &[l, r] = qr[i]; cin >> l >> r; store[r].emplace_back(l, i); } f_lazy_segment_tree_chan<monoid_chan, tag_chan> cover_l_q(2 * n + 1); vector<int> lb(n + 1, 0); for(int i = 1; i <= n; i ++) { int l = b[i], r = a[i]; lb[i] = cover_l_q.query(l, r).mx; lb[i] = max(lb[i], 0); cover_l_q.modify(l, r, tag_chan(i)); } f_lazy_segment_tree_chan<monoid_chan, tag_chan> cover_r_q(2 * n + 1); vector<int> rb(n + 1, n + 1); for(int i = n; i >= 1; i --) { int l = b[i], r = a[i]; rb[i] = cover_r_q.query(l, r).mn; rb[i] = min(rb[i], n + 1); cover_r_q.modify(l, r, tag_chan(i)); } vector<bool> ans(q, false); vector<vector<int>> rem(n + 2); f_lazy_segment_tree_chan<monoid_chan2, tag_chan2> ban_q(n + 1); for(int i = 1; i <= n; i ++) { for(auto j : rem[i]) ban_q.modify(lb[j] + 1, j, tag_chan2(-1)); ban_q.modify(lb[i] + 1, i, tag_chan2(+1)); rem[rb[i]].push_back(i); for(auto [l, idx] : store[i]) ans[idx] = (ban_q.get(l).val == 0); } for(int i = 0; i < q; i ++) cout << (ans[i] ? "Yes" : "No") << endl; } }
#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...
#Verdict Execution timeMemoryGrader output
Fetching results...