#if 0 想定解 time : O((N + Q) lg^2 (Q + N)) space : O((Q + N) lg (Q + N)) 必要のない機能 (lazy, include_i, include_j, ...) は実装を省略している <3, 2> <5/2, 3/2> <1 + _/2, _/2> <- this 上2つはset操作が O(lg N) でできることが証明されてるとかなんとか (この問題の場合は必要ない) 少し高速化 #endif #define NDEBUG // includes {{{ #include #include #include #include #include #include #include #include #include #include #include #include #include #include // #include // #include // #include // #include // }}} using namespace std; using ll = long long; #define DEBUG_OUT std::cerr #define ONLINE // #undef DEBUG // #define DEBUG // DEBUG {{{ #include #include #include #include #include #include #include #include #include template < int n, class... T > typename std::enable_if< (n >= sizeof...(T)) >::type __output_tuple( std::ostream &, std::tuple< T... > const &) {} template < int n, class... T > typename std::enable_if< (n < sizeof...(T)) >::type __output_tuple( std::ostream &os, std::tuple< T... > const &t) { os << (n == 0 ? "" : ", ") << std::get< n >(t); __output_tuple< n + 1 >(os, t); } template < class... T > std::ostream &operator<<(std::ostream &os, std::tuple< T... > const &t) { os << "("; __output_tuple< 0 >(os, t); os << ")"; return os; } template < class T, class U > std::ostream &operator<<(std::ostream &os, std::pair< T, U > const &p) { os << "(" << p.first << ", " << p.second << ")"; return os; } template < class T > std::ostream &operator<<(std::ostream &os, const std::stack< T > &a) { os << "{"; for(auto tmp = a; tmp.size(); tmp.pop()) os << (a.size() == tmp.size() ? "" : ", ") << tmp.top(); os << "}"; return os; } template < class T, class Container, class Compare > std::ostream &operator<<(std::ostream &os, std::priority_queue< T, Container, Compare > a) { os << "{ (top) "; while(a.size()) os << a.top() << (a.size() == 1 ? "" : ", "), a.pop(); os << " }"; return os; } template < class T, class Container > std::ostream &operator<<(std::ostream &os, std::queue< T, Container > a) { os << "{ "; while(a.size()) os << a.front() << (a.size() == 1 ? "" : ", "), a.pop(); os << " }"; return os; } #ifdef DEBUG #if !defined(DEBUG_OUT) #define DEBUG_OUT std::cerr #endif #define dump(...) \ [&]() { \ auto __debug_tap = std::make_tuple(__VA_ARGS__); \ DEBUG_OUT << "[" << __LINE__ << "] " << #__VA_ARGS__ << " = " << __debug_tap \ << std::endl; \ }() template < class T > inline void dump2D(T &d, size_t sizey, size_t sizex) { for(size_t i = 0; i < sizey; i++) { DEBUG_OUT << "\t"; for(size_t j = 0; j < sizex; j++) DEBUG_OUT << d[i][j] << (j + 1 == sizex ? "" : "\t"); DEBUG_OUT << std::endl; } } template < class T > inline void dump1D(T &d, size_t sizey) { for(size_t i = 0; i < sizey; i++) { DEBUG_OUT << d[i] << (i + 1 == sizey ? "" : " "); } DEBUG_OUT << std::endl; } template < class T, class = typename std::iterator_traits< decltype(begin(T())) >::value_type, class = typename std::enable_if< !std::is_same< T, std::string >::value >::type > std::ostream &operator<<(std::ostream &os, const T &a) { os << "{"; for(auto ite = begin(a); ite != end(a); ++ite) os << (ite == begin(a) ? "" : ", ") << *ite; os << "}"; return os; } #else #define dump(...) ((void) 42) #define dump2D(...) ((void) 42) #define dump1D(...) ((void) 42) template < class T, class = typename std::iterator_traits< decltype(begin(T())) >::value_type, class = typename std::enable_if< !std::is_same< T, std::string >::value >::type > std::ostream &operator<<(std::ostream &os, const T &a) { for(auto ite = begin(a); ite != end(a); ++ite) os << (ite == begin(a) ? "" : " ") << *ite; return os; } #endif // }}} /// --- Monoid examples {{{ /// constexpr long long inf_monoid = 1e18 + 100; #include struct Nothing { using T = char; using Monoid = Nothing; using M = T; static constexpr T op(const T &, const T &) { return T(); } static constexpr T identity() { return T(); } template < class X > static constexpr X actInto(const M &, long long, const X &x) { return x; } }; template struct Nothing_M_act { using Monoid = _Monoid; using T = typename Monoid::T; using M = char; static constexpr M op(const T &, const T &) { return T(); } static constexpr M identity() { return T(); } template < class X > static constexpr X actInto(const M &, long long, const X &x) { return x; } }; template < class U = long long > struct RangeMin { using T = U; static T op(const T &a, const T &b) { return std::min< T >(a, b); } static constexpr T identity() { return T(inf_monoid); } }; template < class U = long long > struct RangeMax { using T = U; static T op(const T &a, const T &b) { return std::max< T >(a, b); } static constexpr T identity() { return T(-inf_monoid); } }; template < class U = long long > struct RangeSum { using T = U; static T op(const T &a, const T &b) { return a + b; } static constexpr T identity() { return T(0); } }; template < class U > struct RangeProd { using T = U; static T op(const T &a, const T &b) { return a * b; } static constexpr T identity() { return T(1); } }; template < class U = long long > struct RangeOr { using T = U; static T op(const T &a, const T &b) { return a | b; } static constexpr T identity() { return T(0); } }; #include template < class U = long long > struct RangeAnd { using T = U; static T op(const T &a, const T &b) { return a & b; } static constexpr T identity() { return T(-1); } }; template < size_t N > struct RangeAnd< std::bitset< N > > { using T = std::bitset< N >; static T op(const T &a, const T &b) { return a & b; } static constexpr T identity() { return std::bitset< N >().set(); } }; /// }}}--- /// /// --- M_act examples {{{ /// template < class U = long long, class V = U > struct RangeMinAdd { using X = U; using M = V; using Monoid = RangeMin< U >; static M op(const M &a, const M &b) { return a + b; } static constexpr M identity() { return 0; } static X actInto(const M &m, long long, const X &x) { return m + x; } }; template < class U = long long, class V = U > struct RangeMaxAdd { using X = U; using M = V; using Monoid = RangeMax< U >; static M op(const M &a, const M &b) { return a + b; } static constexpr M identity() { return 0; } static X actInto(const M &m, long long, const X &x) { return m + x; } }; template < class U = long long, class V = U > struct RangeMinSet { using M = U; using Monoid = RangeMin< U >; using X = typename Monoid::T; static M op(const M &a, const M &b) { return a == identity() ? b : a; } static constexpr M identity() { return M(-inf_monoid); } static X actInto(const M &m, long long, const X &x) { return m == identity() ? x : m; } }; template < class U = long long, class V = U > struct RangeMaxSet { using M = U; using Monoid = RangeMax< U >; using X = typename Monoid::T; static M op(const M &a, const M &b) { return a == identity() ? b : a; } static constexpr M identity() { return M(-inf_monoid); } static X actInto(const M &m, long long, const X &x) { return m == identity() ? x : m; } }; template < class U = long long, class V = U > struct RangeSumAdd { using X = U; using M = V; using Monoid = RangeSum< U >; static M op(const M &a, const M &b) { return a + b; } static constexpr M identity() { return 0; } static X actInto(const M &m, long long n, const X &x) { return m * n + x; } }; template < class U = long long, class V = U > struct RangeSumSet { using X = U; using M = V; using Monoid = RangeSum< U >; static M op(const M &a, const M &b) { return a == identity() ? a : b; } static constexpr M identity() { return M(-inf_monoid); } static X actInto(const M &m, long long n, const X &x) { return m == identity() ? x : m * n; } }; template < class U, class V = U > struct RangeProdMul { using X = U; using M = V; using Monoid = RangeProd< U >; static M mpow(M a, long long b) { X r(1); while(b) { if(b & 1) r = r * a; a = a * a; b >>= 1; } return r; } static M op(const M &a, const M &b) { return a * b; } static constexpr M identity() { return M(1); } static X actInto(const M &m, long long n, const X &x) { return x * mpow(m, n); } }; template < class U, class V = U > struct RangeProdSet { using X = U; using M = V; using Monoid = RangeProd< U >; static M op(const M &a, const M &b) { return a == identity() ? b : a; } static constexpr M identity() { return V::unused; } static X actInto(const M &m, long long n, const X &) { if(m == identity()) return; return RangeProdMul< U, V >::mpow(m, n); } }; template < class U = long long, class V = U > struct RangeOrSet { using X = U; using M = V; using Monoid = RangeOr< U >; static M op(const M &a, const M &b) { return a == identity() ? b : a; } static constexpr M identity() { return M(-inf_monoid); } static X actInto(const M &m, long long, const X &x) { return m == identity() ? x : m; } }; template < class U = long long, class V = U > struct RangeAndSet { using X = U; using M = V; using Monoid = RangeAnd< U >; static M op(const M &a, const M &b) { return a == identity() ? b : a; } static constexpr M identity() { return M(-inf_monoid); } static X actInto(const M &m, long long, const X &x) { return m == identity() ? x : m; } }; template < class U = long long, class V = U > struct RangeOr2 { using X = U; using M = V; using Monoid = RangeOr< U >; static M op(const M &a, const M &b) { return a | b; } static constexpr M identity() { return M(0); } static X actInto(const M &m, long long, const X &x) { return m | x; } }; template < class U = long long, class V = U > struct RangeAnd2 { using X = U; using M = V; using Monoid = RangeAnd< U >; static M op(const M &a, const M &b) { return a & b; } static constexpr M identity() { return M(-1); } static X actInto(const M &m, long long, const X &x) { return m & x; } }; template < class U, size_t N > struct RangeAnd2< U, std::bitset< N > > { using X = U; using M = std::bitset< N >; using Monoid = RangeAnd< U >; static M op(const M &a, const M &b) { return a & b; } static constexpr M identity() { return std::bitset< N >().set(); } static X actInto(const M &m, long long, const X &x) { return m & x; } }; /// }}}--- /// #include #include #include #include #include #include namespace wbt { // WeightBalancedTreeNode {{{ template < class Key, class M_act > struct WeightBalancedTreeNode { using size_type = std::size_t; using node_type = WeightBalancedTreeNode; using pointer = WeightBalancedTreeNode *; using const_pointer = const WeightBalancedTreeNode *; using Monoid = typename M_act::Monoid; using T = typename Monoid::T; using M = typename M_act::M; size_type sz; Key key; T value = Monoid::identity(), accum = Monoid::identity(); pointer l, r; size_type weight() const { return sz + 1; } bool bounded_balanced() const { if(this == get_NIL()) return 1; return is_balanced(l, r) && is_balanced(r, l) && l->bounded_balanced() && r->bounded_balanced(); } static long long sq(long long a) { return a * a; }; static bool is_balanced(const_pointer a, const_pointer b) { // return delta * a->weight() >= b->weight(); // delta = 3 // return 3 * a->weight() >= b->weight(); // delta = 5 / 2 // return 5 * a->weight() >= 2 * b->weight(); // delta = 1 + _/2 // (1 + _/2) a >= b // _/2 a >= b - a // 2 a^2 >= (b - a)^2 return 2 * sq(a->weight()) >= sq(static_cast(a->weight()) - static_cast(b->weight())); } static bool is_single(const_pointer a, const_pointer b) { // return a->weight() < gamma * b->weight(); // gamma = 2 // return a->weight() < 2 * b->weight(); // gamma = 3 / 2 // return 2 * a->weight() < 3 * b->weight(); // gamma = _/2 return sq(a->weight()) < 2 * sq(b->weight()); } static std::pair< T, bool > lookup(const_pointer p, Key key) { const_pointer t = p; while(t != get_NIL()) { if(key < t->key) { t = t->l; } else if(t->key < key) { t = t->r; } else { return std::pair< T, bool >(t->value, 1); } } return std::pair< T, bool >(); } static pointer copy(const_pointer a) { if(a == get_NIL()) return get_NIL(); return make(a->key, a->value, a->accum, copy(a->l), copy(a->r)); } static T fold(const_pointer p, Key keyL, Key keyR, bool include_left, bool include_right) { while(p != get_NIL()) { if(p->key < keyL || (!include_left && !(keyL < p->key))) p = p->r; else if(keyR < p->key || (!include_right && !(p->key < keyR))) p = p->l; else break; } if(p == get_NIL()) return Monoid::identity(); T x = p->value; const_pointer pl = p->l, pr = p->r; while(pl != get_NIL()) { if(pl->key < keyL) { pl = pl->r; } else { x = Monoid::op(pl->r->accum, x); if(keyL < pl->key) { x = Monoid::op(pl->value, x); pl = pl->l; } else { if(include_left) x = Monoid::op(pl->value, x); break; } } } while(pr != get_NIL()) { if(keyR < pr->key) { pr = pr->l; } else { x = Monoid::op(x, pr->l->accum); if(pr->key < keyR) { x = Monoid::op(x, pr->value); pr = pr->r; } else { if(include_right) x = Monoid::op(x, pr->value); break; } } } return x; } static size_type count(const_pointer p, const Key &keyL, const Key &keyR, bool include_left, bool include_right) { if(keyR < keyL) return 0; const_pointer t = p; while(t != get_NIL()) { if(!(keyL < t->key)) { // key <= keyL if(include_left && !(t->key < keyL)) return 1 + count_lesser(t->r, keyR, include_right); t = t->r; } else if(!(t->key < keyR)) { // keyR <= key if(include_right && !(keyR < t->key)) return 1 + count_greater(t->l, keyL, include_left); t = t->l; } else { // keyL < key < keyR return count_greater(t->l, keyL, include_left) + 1 + count_lesser(t->r, keyR, include_right); } } return 0; } static size_type count_lesser(const_pointer p, const Key &keyR, bool include_bound) { size_type res = 0; const_pointer t = p; while(t != get_NIL()) { if(t->key < keyR) { res += t->l->sz + 1; t = t->r; } else { // keyR <= key if(include_bound && !(keyR < t->key)) return res + t->l->sz + 1; t = t->l; } } return res; } static size_type count_greater(const_pointer p, const Key &keyL, bool include_bound) { size_type res = 0; const_pointer t = p; while(t != get_NIL()) { if(keyL < t->key) { res += t->r->sz + 1; t = t->l; } else { // key <= keyL if(include_bound && !(t->key < keyL)) return res + t->r->sz + 1; t = t->r; } } return res; } static pointer insert(pointer p, Key key, T value, bool is_identity) { if(p == get_NIL()) return make_singleton(key, value); static std::vector< std::pair< pointer, bool > > pts; pointer t = p; while(t != get_NIL()) { if(key < t->key) { pts.emplace_back(t, 1); t = t->l; } else if(t->key < key) { pts.emplace_back(t, 0); t = t->r; } else { pts.clear(); return p; } } pointer q; bool is_left; std::tie(q, is_left) = pts.back(); (is_left ? q->l : q->r) = make_singleton(key, value); while(pts.size()) { std::tie(q, is_left) = pts.back(); pts.pop_back(); update(q, is_identity); if(is_left) { balanceR(q); } else { balanceL(q); } } return p; } static pointer insert_min(pointer p, Key key, T value, bool is_identity) { if(p == get_NIL()) return make_singleton(key, value); static std::vector< pointer > pts; pointer t = p; while(t != get_NIL()) { pts.emplace_back(t); t = t->l; } pointer q = pts.back(); q->l = make_singleton(key, value); while(pts.size()) { q = pts.back(); pts.pop_back(); update(q, is_identity); balanceR(q); } return p; } static pointer insert_max(pointer p, Key key, T value, bool is_identity) { if(p == get_NIL()) return make_singleton(key, value); static std::vector< pointer > pts; pointer t = p; while(t != get_NIL()) { pts.emplace_back(t); t = t->r; } pointer q = pts.back(); q->r = make_singleton(key, value); while(pts.size()) { q = pts.back(); pts.pop_back(); update(q, is_identity); balanceR(q); } return p; } static pointer erase(pointer p, Key key) { static std::vector< std::pair< pointer, bool > > pts; pointer t = p; while(t != get_NIL()) { if(key < t->key) { pts.emplace_back(t, 1); t = t->l; } else if(t->key < key) { pts.emplace_back(t, 0); t = t->r; } else { pointer s = glue(t->l, t->r); delete t; if(pts.empty()) return s; pointer q; bool is_left; std::tie(q, is_left) = pts.back(); (is_left ? q->l : q->r) = s; while(pts.size()) { std::tie(q, is_left) = pts.back(); pts.pop_back(); update(q); if(is_left) { balanceL(q); } else { balanceR(q); } } break; } } pts.clear(); return p; } Key select(size_type k) const { assert(this != get_NIL()); if(k < l->sz) return l->select(k); k -= l->sz; if(k == 0) return key; k--; return r->select(k); } static pointer balance(Key k, T v, pointer l, pointer r) { if(is_balanced(l, r) && is_balanced(r, l)) return make(k, v, l, r); if(l->sz > r->sz) return rotateR(k, v, l, r); return rotateL(k, v, l, r); } static pointer glue(pointer l, pointer r) { if(l == get_NIL()) return r; if(r == get_NIL()) return l; if(l->sz > r->sz) { pointer l2, p; std::tie(l2, p) = delete_find_max(l); p->l = l2; p->r = r; update(p); balanceL(p); return p; } else { pointer r2, p; std::tie(r2, p) = delete_find_min(r); p->l = l; p->r = r2; update(p); balanceR(p); return p; } } // BST basic operations {{{ static pointer merge(pointer l, Key k, T v, pointer r) { static std::vector< std::pair< pointer, bool > > pts; pointer q; while(1) { if(l == get_NIL()) { q = insert_min(r, k, v, 0); break; } if(r == get_NIL()) { q = insert_max(l, k, v, 0); break; } bool bal1 = is_balanced(l, r); bool bal2 = is_balanced(r, l); if(bal1 && bal2) { q = make(k, v, l, r); break; } else if(bal1) { pts.emplace_back(l, 1); l = l->r; } else { pts.emplace_back(r, 0); r = r->l; } } while(pts.size()) { pointer p; bool is_left; std::tie(p, is_left) = pts.back(); pts.pop_back(); (is_left ? p->r : p->l) = q; q = p; update(q); if(is_left) { balanceL(q); } else { balanceR(q); } } return q; } static std::tuple< pointer, bool, pointer > split(pointer a, const Key &k) { static std::vector< std::pair< pointer, int > > pts; bool erased = 0; while(1) { if(a == get_NIL()) break; if(k < a->key) { pts.emplace_back(a, 1); a = a->l; } else if(a->key < k) { pts.emplace_back(a, 0); a = a->r; } else { erased = 1; break; } } pointer l = a->l, r = a->r; if(a != get_NIL()) delete a; while(pts.size()) { pointer p; bool is_left; std::tie(p, is_left) = pts.back(); pts.pop_back(); if(is_left) { r = merge(r, std::move(p->key), std::move(p->value), p->r); } else { l = merge(p->l, std::move(p->key), std::move(p->value), l); } delete p; } return std::tuple< pointer, bool, pointer >(l, erased, r); } // }}} // set operations {{{ static pointer unionL(pointer t1, pointer t2) { if(t1 == get_NIL()) return t2; if(t2 == get_NIL()) return t1; // if(t1->sz < t2->sz) swap(t1, t2); pointer t_lesser, t_greater; std::tie(t_lesser, std::ignore, t_greater) = split(t2, t1->key); pointer q = merge(unionL(t1->l, t_lesser), std::move(t1->key), std::move(t1->value), unionL(t1->r, t_greater)); delete t1; return q; } // }}} using PP = std::tuple< pointer, pointer >; static PP delete_find_max(pointer p) { assert(p != get_NIL()); if(p->r == get_NIL()) { pointer q = p->l; p->l = get_NIL(); update(p); return PP(q, p); } pointer t = p; static std::vector pts; while(1) { pts.push_back(t); if(t->r->r == get_NIL()) { pointer q = t->r; t->r = q->l; q->l = get_NIL(); update(q); while(pts.size()) { pointer s = pts.back(); pts.pop_back(); update(s); } return PP(p, q); } else { t = t->r; } } } static PP delete_find_min(pointer p) { assert(p != get_NIL()); if(p->l == get_NIL()) { pointer q = p->r; p->r = get_NIL(); update(p); return PP(q, p); } pointer t = p; static std::vector pts; while(1) { pts.push_back(t); if(t->l->l == get_NIL()) { pointer q = t->l; t->l = q->r; q->r = get_NIL(); update(q); while(pts.size()) { pointer s = pts.back(); pts.pop_back(); update(s); } return PP(p, q); } else { t = t->l; } } } // rotate {{{ static void balanceL(pointer p) { if(is_balanced(p->l, p->r)) return; rotateL(p); } static void balanceR(pointer p) { if(is_balanced(p->r, p->l)) return; rotateR(p); } static void rotateL(pointer p) { const pointer rl = p->r->l, rr = p->r->r; if(is_single(rl, rr)) { singleL(p); } else { doubleL(p); } } static void rotateR(pointer p) { const pointer ll = p->l->l, lr = p->l->r; if(is_single(lr, ll)) { singleR(p); } else { doubleR(p); } } static void singleL(pointer p) { pointer q = p->r; assert(q != get_NIL()); p->r = q->r; q->r = q->l; q->l = p->l; p->l = q; std::swap(p->key, q->key); std::swap(p->value, q->value); update(q); update(p); } static void singleR(pointer p) { pointer q = p->l; assert(q != get_NIL()); p->l = q->l; q->l = q->r; q->r = p->r; p->r = q; std::swap(p->key, q->key); std::swap(p->value, q->value); update(q); update(p); } static void doubleL(pointer p) { pointer s = p->r->l; assert(s != get_NIL()); p->r->l = s->r; s->r = s->l; s->l = p->l; p->l = s; std::swap(p->key, s->key); std::swap(p->value, s->value); update(p->l); update(p->r); update(p); } static void doubleR(pointer p) { pointer s = p->l->r; assert(s != get_NIL()); p->l->r = s->l; s->l = s->r; s->r = p->r; p->r = s; std::swap(p->key, s->key); std::swap(p->value, s->value); update(p->l); update(p->r); update(p); } // }}} static pointer get_NIL() { static pointer NIL = make_NIL(); return NIL; } static pointer make_NIL() { pointer p = new WeightBalancedTreeNode; p->sz = 0; p->value = p->accum = Monoid::identity(); p->l = p; p->r = p; return p; } static pointer make_singleton(Key key, T value) { pointer p = new WeightBalancedTreeNode; p->sz = 1; p->key = std::move(key); p->value = p->accum = std::move(value); p->l = get_NIL(); p->r = get_NIL(); return p; } static pointer make(Key key, T value, pointer l, pointer r) { pointer p = new WeightBalancedTreeNode; p->sz = l->sz + r->sz + 1; p->key = std::move(key); p->value = value; p->accum = Monoid::op(Monoid::op(l->accum, std::move(value)), r->accum); p->l = l; p->r = r; return p; } static void update(pointer p, bool is_identity = 0) { p->sz = p->l->sz + p->r->sz + 1; if(!is_identity) p->accum = Monoid::op(Monoid::op(p->l->accum, p->value), p->r->accum); } static pointer make(Key key, T value, T accum, pointer l, pointer r) { pointer p = new WeightBalancedTreeNode; p->sz = l->sz + r->sz + 1; p->key = std::move(key); p->value = std::move(value); p->accum = std::move(accum); p->l = l; p->r = r; return p; } static std::pair< Key, T > get_min(const_pointer p) { assert(p != get_NIL()); while(p->l != get_NIL()) p = p->l; return std::pair< Key, T >(p->key, p->value); } static std::pair< Key, T > get_max(const_pointer p) { assert(p != get_NIL()); while(p->r != get_NIL()) p = p->r; return std::pair< Key, T >(p->key, p->value); } void get_all_dfs(std::vector< std::pair< Key, T > > &res) const { if(this == get_NIL()) return; l->get_all_dfs(res); res.emplace_back(key, value); r->get_all_dfs(res); } static void delete_all(pointer p) { if(p == get_NIL()) return; delete_all(p->l); delete_all(p->r); delete p; } using touch_func = std::function< void(Key key, T &v, T &accum, bool eq) >; static bool touch_path_to(pointer p, const Key &target, const touch_func &touch) { pointer t = p; static std::vector< pointer > pts; while(t != get_NIL()) { if(target < t->key) { pts.push_back(t); t = t->l; } else if(t->key < target) { pts.push_back(t); t = t->r; } else { touch(t->key, t->value, t->accum, 1); while(pts.size()) { t = pts.back(); pts.pop_back(); touch(t->key, t->value, t->accum, 0); } return 1; } } pts.clear(); return 0; } }; // }}} // WeightBalancedTree {{{ template < class Key, class M_act > struct WeightBalancedTree { using size_type = std::size_t; using node_type = WeightBalancedTreeNode< Key, M_act >; using pointer = WeightBalancedTreeNode< Key, M_act > *; using const_pointer = const WeightBalancedTreeNode< Key, M_act > *; using Monoid = typename M_act::Monoid; using T = typename Monoid::T; using M = typename M_act::M; bool active = 1; pointer p = node_type::get_NIL(); WeightBalancedTree() {} WeightBalancedTree(pointer p) : p(p) {} WeightBalancedTree(const WeightBalancedTree &wbt) { *this = wbt; } WeightBalancedTree(WeightBalancedTree &&wbt) { *this = std::move(wbt); } WeightBalancedTree &operator=(const WeightBalancedTree &wbt) { assert(wbt.active); if(active) node_type::delete_all(p); active = 1; p = node_type::copy(wbt.p); return *this; } WeightBalancedTree &operator=(WeightBalancedTree &&wbt) { assert(wbt.active); if(active) node_type::delete_all(p); active = 1; wbt.active = 0; p = wbt.p; return *this; } ~WeightBalancedTree() { if(active) { node_type::delete_all(p); } } void insert(Key key, T value, bool is_identity = 0) { assert(active); p = node_type::insert(p, key, value, is_identity); } void insert(Key key) { insert(key, Monoid::identity(), 1); } bool erase(Key key) { assert(active); p = node_type::erase(p, key); // TODO return 1; } std::pair< T, bool > lookup(Key key) const { assert(active); return node_type::lookup(p, key); } T get(Key key) const { assert(active); return lookup(key).first; } size_type count(Key key) const { assert(active); return lookup(key).second; } void clear() { if(p == node_type::get_NIL()) { active = 1; return; } if(active) node_type::delete_all(p); active = 1; p = node_type::get_NIL(); } std::vector< std::pair< Key, T > > get_all() const { assert(active); std::vector< std::pair< Key, T > > res; res.reserve(size()); p->get_all_dfs(res); return res; } T fold(Key keyL, Key keyR) const { assert(active); return node_type::fold(p, keyL, keyR, 1, 0); } T fold(Key keyL, Key keyR, bool include_left, bool include_right) const { assert(active); return node_type::fold(p, keyL, keyR, include_left, include_right); } std::pair< Key, T > get_min() const { assert(active); return p->get_min(); } std::pair< Key, T > get_max() const { assert(active); return p->get_max(); } size_type count(Key l, Key r) const { assert(active); return node_type::count(p, l, r, 1, 0); } size_type count(Key l, Key r, bool include_left, bool include_right) const { assert(active); return node_type::count(p, l, r, include_left, include_right); } size_type count_lesser(Key key, bool include_bound) const { assert(active); return node_type::count_lesser(p, key, include_bound); } size_type count_greater(Key key, bool include_bound) const { assert(active); return node_type::count_greater(p, key, include_bound); } Key select(size_type k) const { assert(active); assert(k < size()); return p->select(k); } WeightBalancedTree &union_with(WeightBalancedTree &&a) { assert(active && a.active); a.active = 0; p = node_type::unionL(p, a.p); return *this; } using touch_func = std::function< void(Key key, T &v, T &accum, bool eq) >; static touch_func touch_default; void touch_path_to(const Key &target, const touch_func &touch) { assert(active); node_type::touch_path_to(p, target, touch); } size_type size() const { assert(active); return p->sz; } bool empty() const { assert(active); return p == node_type::get_NIL(); } }; template < class Key, class M_act > typename WeightBalancedTree< Key, M_act >::touch_func WeightBalancedTree< Key, M_act >::touch_default = [](...) {}; // }}} } template < class Key, class M_act > using WBT = wbt::WeightBalancedTree< Key, M_act >; /// --- RangeMedianWithUpdate {{{ /// #include namespace wbt { template < class _T, class _Monoid, class Index = long long > struct RangeMedianWithUpdate { using size_type = std::size_t; using T = _T; using Monoid = _Monoid; using X = typename Monoid::T; struct Point { Index x; T y; bool minus_inf = 0; Point() {} Point(Index x) : x(x), minus_inf(1) {} Point(Index x, T y) : x(x), y(y) {} bool operator<(const Point &a) const { if(x < a.x) return 1; if(a.x < x) return 0; if(a.minus_inf) return 0; if(minus_inf) return 1; return 0; } friend std::ostream &operator<<(std::ostream &os, Point a) { if(a.minus_inf) os << "(" << a.x << ", " << "-inf" << ")"; else os << "(" << a.x << ", " << a.y << ")"; return os; } }; struct RMWU_Monoid { using T = WeightBalancedTree< Point, Nothing_M_act >; static T op(T a, T b) { return a.union_with(std::move(b)); } static T identity() { return T(); } }; struct RMWU_M_act { using Monoid = RMWU_Monoid; using X = typename Monoid::T; using M = char; static M op(const M &, const M &) { return 0; } static constexpr M identity() { return 0; } static X actInto(const M &, long long, const X &x) { return x; } }; using T_SET = typename RMWU_Monoid::T; using WBT = WeightBalancedTree< T, RMWU_M_act >; using pointer = typename WBT::pointer; using const_pointer = typename WBT::const_pointer; WeightBalancedTree< T, RMWU_M_act > wbt; RangeMedianWithUpdate() {} static RangeMedianWithUpdate with2(const std::vector< std::tuple< T, X > > &v, Index start = 0) { std::vector< std::tuple< Index, T, X > > w; w.reserve(v.size()); for(size_type i = 0; i < v.size(); ++i, ++start) w.emplace_back(start, std::get< 0 >(v[i]), std::get< 1 >(v[i])); return with3(w); } static RangeMedianWithUpdate with3(std::vector< std::tuple< Index, T, X > > v) { RangeMedianWithUpdate res; using V = std::tuple< Index, T, X >; std::sort(v.begin(), v.end(), [](const V &a, const V &b) { return std::get< 1 >(a) < std::get< 1 >(b); }); static std::queue< std::pair< size_type, size_type > > q; q.emplace(0, v.size()); while(q.size()) { Index l, r; std::tie(l, r) = q.front(); q.pop(); if(l == r) continue; Index m = (l + r) / 2; res.insert(std::get< 0 >(v[m]), std::get< 1 >(v[m]), std::get< 2 >(v[m])); q.emplace(l, m); q.emplace(m + 1, r); } return res; } void insert(Index i, T v, X x, bool is_identity = 0) { wbt.insert(v); insert_path_to(wbt.p, v, Point(i, v), x, is_identity); } void insert(Index i, T v) { insert(i, v, Monoid::identity(), 1); } bool erase(Index i, T v) { return erase_path_to(wbt.p, v, Point(i, v)); } static bool insert_path_to(pointer p, T target, const Point &v, X x, bool is_identity) { pointer t = p; static std::vector< pointer > pts; while(t != WBT::node_type::get_NIL()) { if(target < t->key) { pts.push_back(t); t = t->l; } else if(t->key < target) { pts.push_back(t); t = t->r; } else { t->value.insert(v, x, is_identity); t->accum.insert(v, x, is_identity); while(pts.size()) { t = pts.back(); pts.pop_back(); t->accum.insert(v, x, is_identity); } return 1; } } pts.clear(); return 0; } static bool erase_path_to(pointer p, T target, const Point &v) { pointer t = p; static std::vector< pointer > pts; while(t != WBT::node_type::get_NIL()) { if(target < t->key) { pts.push_back(t); t = t->l; } else if(t->key < target) { pts.push_back(t); t = t->r; } else { t->value.erase(v); t->accum.erase(v); while(pts.size()) { t = pts.back(); pts.pop_back(); t->accum.erase(v); } return 1; } } pts.clear(); return 0; } X rect_fold(Index i, Index j, T l, T r) { return rect_fold(i, j, l, r, 1, 0, 1, 0); } X rect_fold(Index i, Index j, T l, T r, bool include_i, bool include_j, bool include_l, bool include_r) const { const_pointer p = wbt.p; while(p != WBT::node_type::get_NIL()) { if(p->key < l || (!include_l && !(l < p->key))) p = p->r; else if(r < p->key || (!include_r && !(p->key < r))) p = p->l; else break; } if(p == WBT::node_type::get_NIL()) return Monoid::identity(); X x = p->value.fold(i, j); const_pointer pl = p->l, pr = p->r; while(pl != WBT::node_type::get_NIL()) { if(pl->key < l) { pl = pl->r; } else { x = Monoid::op(pl->r->accum.fold(i, j), x); if(l < pl->key) { x = Monoid::op(pl->value.fold(i, j), x); pl = pl->l; } else { if(include_l) x = Monoid::op(pl->value.fold(i, j), x); break; } } } while(pr != WBT::node_type::get_NIL()) { if(r < pr->key) { pr = pr->l; } else { x = Monoid::op(x, pr->l->accum.fold(i, j)); if(pr->key < r) { x = Monoid::op(x, pr->value.fold(i, j)); pr = pr->r; } else { if(include_r) x = Monoid::op(x, pr->value.fold(i, j)); break; } } } return x; } Point range_select(Index i, Index j, size_type k) const { return range_select_dfs(wbt.p, i, j, k); } size_type range_count_smaller(Index i, Index j, T x, bool include_bound) const { return range_count_smaller_dfs(wbt.p, i, j, x, include_bound); } private: Point range_select_dfs(const_pointer p, Index i, Index j, size_type k) const { assert(p != WBT::node_type::get_NIL()); assert(k < p->accum.count(i, j)); size_type lsz = p->l->accum.count(i, j); if(k < lsz) { return range_select_dfs(p->l, i, j, k); } k -= lsz; size_type hsz = p->value.count(i, j); if(k < hsz) { return p->value.select(p->value.count_lesser(i, 0) + k); } k -= hsz; return range_select_dfs(p->r, i, j, k); } size_type range_count_smaller_dfs(const_pointer p, Index i, Index j, T x, bool include_bound) const { if(p == WBT::node_type::get_NIL()) return 0; if(x < p->key) return range_count_smaller_dfs(p->l, i, j, x, include_bound); // p->key <= x size_type lsz = p->l->accum.count(i, j); size_type hsz = p->value.count(i, j); if(!(p->key < x)) { if(include_bound) return lsz + hsz; return lsz; } return lsz + hsz + range_count_smaller_dfs(p->r, i, j, x, include_bound); } public: Point range_median(Index i, Index j, bool choose_greater = 0) const { return range_select(i, j, (count(i, j) - 1 + choose_greater) / 2); } size_type count(Index i, Index j) const { return wbt.p->accum.count(i, j); } size_type size() const { return wbt.p->accum.size(); } }; } /// }}}--- /// template < class T, class Monoid, class Index = long long > using RangeMedianWithUpdate = wbt::RangeMedianWithUpdate< T, Monoid, Index >; constexpr int N = 1 << 16; constexpr ll inf = 1ll << 40; // 1e12 int n, q; ll t[N], l[N], r[N]; ll med[N], smaller[N], bigger[N]; int main() { std::ios::sync_with_stdio(false), std::cin.tie(0); cin >> n >> q; assert(1 <= n && n < N); assert(1 <= q && q < N); vector< ll > v(n + 1); vector> ini; for(int i = 1; i <= n; i++) { cin >> v[i]; // rm.insert(i, v[i], v[i]); ini.emplace_back(i, v[i], v[i]); assert(0 <= v[i] && v[i] < inf); } auto rm = RangeMedianWithUpdate< ll, RangeSum >::with3(ini); for(int i = 0; i < q; i++) cin >> t[i] >> l[i] >> r[i]; auto w = v; ll sum16 = 0, sum40 = 0; for(int i = 0; i < q; i++) { if(t[i] == 1) { // update #ifdef ONLINE l[i] ^= sum16; r[i] ^= sum40; #endif assert(1 <= l[i] && l[i] <= n); assert(0 <= r[i] && r[i] < inf); // cout << "1 " << l[i] << " " << r[i] << "\n"; rm.erase(l[i], w[l[i]]); rm.insert(l[i], r[i], r[i]); w[l[i]] = r[i]; } else { // query #ifdef ONLINE l[i] ^= sum16; r[i] ^= sum16; #endif if(l[i] > r[i]) swap(l[i], r[i]); // cout << "2 " << l[i] << " " << r[i] << "\n"; assert(1 <= l[i] && l[i] <= n); assert(1 <= r[i] && r[i] <= n); assert(l[i] < r[i]); r[i]++; int len = r[i] - l[i]; med[i] = rm.range_median(l[i], r[i]).y; smaller[i] = rm.range_count_smaller(l[i], r[i], med[i], 0); bigger[i] = len - rm.range_count_smaller(l[i], r[i], med[i], 1); ll z = 0; z -= rm.rect_fold(l[i], r[i], 0, med[i]); z += rm.rect_fold(l[i], r[i], med[i] + 1, inf); z -= ll(len / 2 - smaller[i]) * med[i]; z += ll((len - len / 2) - bigger[i]) * med[i]; if(len % 2 == 1) z -= med[i]; sum16 ^= z % N; sum40 ^= z % (1ll << 40); cout << z << "\n"; } } return 0; }