#pragma once #include "../../kyopro_library/template.hpp" /// @brief セグメント木 /// @ref verify: https://judge.yosupo.jp/problem/point_set_range_composite /// @ref verify: https://judge.yosupo.jp/problem/vertex_set_path_composite /// @ref verify: https://judge.yosupo.jp/problem/majority_voting template struct SegTree { using Type = typename Monoid::Type; SegTree() = default; /// @brief 要素数 n のセグ木を構築する SegTree(int n) { this->n = n; dat = vector(n << 1, Monoid::id()); cand.reserve(100); cand_l.reserve(100); cand_r.reserve(100); } /// @brief 配列 v からセグ木を構築する /// @note O(N) SegTree(const vector& v) { this->n = v.size(); dat = vector(n << 1, Monoid::id()); rep(i, n) dat[i + n] = v[i]; for(int i = n - 1; i > 0; i--) dat[i] = Monoid::op(dat[i << 1], dat[i << 1 | 1]); cand.reserve(100); cand_l.reserve(100); cand_r.reserve(100); } /// @brief i 番目の要素を x に変更する /// @note O(log(N)) void set(int i, Type x) { i += n; dat[i] = x; while(i >>= 1) dat[i] = Monoid::op(dat[i << 1], dat[i << 1 | 1]); } /// @brief 区間 [l, r) のモノイド積を返す /// @note O(log(N)) Type fold(int l, int r) { Type retl = Monoid::id(), retr = Monoid::id(); l += n; r += n; while(l < r) { if(l & 1) retl = Monoid::op(retl, dat[l++]); if(r & 1) retr = Monoid::op(dat[--r], retr); l >>= 1; r >>= 1; } return Monoid::op(retl, retr); } /// @brief 区間 [l, x) のモノイド積が f を満たすような最大の x >= l を返す /// @attention `f(Monoid::id())=true` が成り立つ必要がある /// @note O(log(N)) template int find_right(int l, F f) { assert(f(Monoid::id())); if(l == n) return n; l += n; int r = n + n; cand_l.clear(); cand_r.clear(); while(l < r) { if(l & 1) cand_l.push_back(l++); if(r & 1) cand_r.push_back(--r); l >>= 1; r >>= 1; } cand = cand_l; reverse(all(cand_r)); cand.insert(cand.end(), all(cand_r)); Type val = Monoid::id(); for(int i : cand) { if(f(Monoid::op(val, dat[i]))) { val = Monoid::op(val, dat[i]); } else { while(i < n) { i <<= 1; if(f(Monoid::op(val, dat[i]))) { val = Monoid::op(val, dat[i]); i |= 1; } } return i - n; } } return n; } /// @brief 区間 [x, r) のモノイド積が f を満たすような最小の x <= r を返す /// @attention `f(Monoid::id())=true` が成り立つ必要がある /// @note O(log(N)) template int find_left(int r, F f) { assert(f(Monoid::id())); if(r == 0) return 0; r += n; int l = n; cand_l.clear(); cand_r.clear(); while(l < r) { if(l & 1) cand_l.push_back(l++); if(r & 1) cand_r.push_back(--r); l >>= 1; r >>= 1; } cand = cand_r; reverse(all(cand_l)); cand.insert(cand.end(), all(cand_l)); Type val = Monoid::id(); for(int i : cand) { if(f(Monoid::op(dat[i], val))) { val = Monoid::op(dat[i], val); } else { while(i < n) { i = (i << 1) | 1; if(f(Monoid::op(dat[i], val))) { val = Monoid::op(dat[i], val); i ^= 1; } } return i - n + 1; } } return 0; } /// @brief i 番目の要素を返す /// @note O(1) Type operator[](int i) { return dat[i + n]; } /// @brief 配列のサイズを返す int size() { return n; } Type get(int i) { return dat[i + n]; } private: int n; vector dat; vi cand, cand_l, cand_r; }; #include "../../kyopro_library/others/monoid.hpp" /// @brief 区間クエリ namespace RangeQuery { /// @brief 1点変更 / 区間 min template > struct Min { using Type = struct SegTree>; }; /// @brief 1点変更 / 区間 max template > struct Max { using Type = struct SegTree>; }; /// @brief 1点変更 / 区間和 template struct Sum { using Type = struct SegTree>; }; } // namespace RangeQuery