/* * Disclaimer: All code enclosed within “namespace zawa” is available at the following link. * https://zawa-tin.github.io/cp-documentation/ */ #include #include #include #include #include #include #include #include #include #include // #include "Src/Number/IntegerDivision.hpp" // #include "Src/Utility/BinarySearch.hpp" // #include "Src/Sequence/CompressedSequence.hpp" // #include "Src/Sequence/RunLengthEncoding.hpp" // #include "Src/Algebra/Group/AdditiveGroup.hpp" // #include "Src/DataStructure/FenwickTree/FenwickTree.hpp" #include #include namespace zawa { using i16 = std::int16_t; using i32 = std::int32_t; using i64 = std::int64_t; using i128 = __int128_t; using u8 = std::uint8_t; using u16 = std::uint16_t; using u32 = std::uint32_t; using u64 = std::uint64_t; using usize = std::size_t; } // namespace zawa #include namespace zawa { namespace concepts { template concept Semigroup = requires { typename T::Element; { T::operation(std::declval(), std::declval()) } -> std::same_as; }; } // namespace concepts } // namespace zawa namespace zawa { namespace concepts { template concept Identitiable = requires { typename T::Element; { T::identity() } -> std::same_as; }; template concept Monoid = Semigroup and Identitiable; } // namespace } // namespace zawa #include #include #include namespace zawa { template class SegmentTree { public: using VM = Monoid; using V = typename VM::Element; using OM = Monoid; using O = typename OM::Element; SegmentTree() = default; explicit SegmentTree(usize n) : m_n{ n }, m_dat(n << 1, VM::identity()) {} explicit SegmentTree(const std::vector& dat) : m_n{ dat.size() }, m_dat(dat.size() << 1, VM::identity()) { for (usize i{} ; i < m_n ; i++) { m_dat[i + m_n] = dat[i]; } for (usize i{m_n} ; i-- ; ) { m_dat[i] = VM::operation(m_dat[left(i)], m_dat[right(i)]); } } [[nodiscard]] inline usize size() const noexcept { return m_n; } [[nodiscard]] V get(usize i) const { assert(i < size()); return m_dat[i + m_n]; } [[nodiscard]] V operator[](usize i) const { assert(i < size()); return m_dat[i + m_n]; } void operation(usize i, const O& value) { assert(i < size()); i += size(); m_dat[i] = OM::operation(m_dat[i], value); while (i = parent(i), i) { m_dat[i] = VM::operation(m_dat[left(i)], m_dat[right(i)]); } } void assign(usize i, const V& value) { assert(i < size()); i += size(); m_dat[i] = value; while (i = parent(i), i) { m_dat[i] = VM::operation(m_dat[left(i)], m_dat[right(i)]); } } [[nodiscard]] V product(u32 l, u32 r) const { assert(l <= r and r <= size()); V L{ VM::identity() }, R{ VM::identity() }; for (l += size(), r += size() ; l < r ; l = parent(l), r = parent(r)) { if (l & 1) { L = VM::operation(L, m_dat[l++]); } if (r & 1) { R = VM::operation(m_dat[--r], R); } } return VM::operation(L, R); } template requires std::predicate [[nodiscard]] usize maxRight(usize l, const F& f) { assert(l < size()); static_assert(std::is_convertible_v>, "maxRight's argument f must be function bool(T)"); assert(f(VM::identity())); usize res{l}, width{1}; V prod{ VM::identity() }; for (l += size() ; res + width <= size() ; l = parent(l), width <<= 1) if (l & 1) { if (not f(VM::operation(prod, m_dat[l]))) break; res += width; prod = VM::operation(prod, m_dat[l++]); } while (l = left(l), width >>= 1) { if (res + width <= size() and f(VM::operation(prod, m_dat[l]))) { res += width; prod = VM::operation(prod, m_dat[l++]); } } return res; } template requires std::predicate [[nodiscard]] usize minLeft(usize r, const F& f) const { assert(r <= size()); static_assert(std::is_convertible_v>, "minLeft's argument f must be function bool(T)"); assert(f(VM::identity())); usize res{r}, width{1}; V prod{ VM::identity() }; for (r += size() ; res >= width ; r = parent(r), width <<= 1) if (r & 1) { if (not f(VM::operation(m_dat[r - 1], prod))) break; res -= width; prod = VM::operation(prod, m_dat[--r]); } while (r = left(r), width >>= 1) { if (res >= width and f(VM::operation(m_dat[r - 1], prod))) { res -= width; prod = VM::operation(m_dat[--r], prod); } } return res; } friend std::ostream& operator<<(std::ostream& os, const SegmentTree& st) { for (usize i{1} ; i < 2 * st.size() ; i++) { os << st.m_dat[i] << (i + 1 == 2 * st.size() ? "" : " "); } return os; } private: constexpr u32 left(u32 v) const { return v << 1; } constexpr u32 right(u32 v) const { return v << 1 | 1; } constexpr u32 parent(u32 v) const { return v >> 1; } usize m_n; std::vector m_dat; }; } // namespace zawa // #include "Src/DataStructure/DisjointSetUnion/DisjointSetUnion.hpp" // #include "Src/DataStructure/Heap/BinaryHeap.hpp" #include #include #include namespace zawa { template class ConstantSquareMatrix { static_assert(N > 0,"ConstantSquareMatrix::N must be positive"); public: using T = typename Semiring::Element; using A = typename Semiring::Addition; using M = typename Semiring::Multiplication; using Element = ConstantSquareMatrix; constexpr ConstantSquareMatrix() { m_data.fill(A::identity()); } constexpr explicit ConstantSquareMatrix(const std::array& data) : m_data{data} {} constexpr explicit ConstantSquareMatrix(const std::array,N>& data) { for (usize i = 0 ; i < N ; i++) for (usize j = 0 ; j < N ; j++) m_data[i*N+j] = data[i][j]; } constexpr explicit ConstantSquareMatrix(std::initializer_list> data) { assert(data.size() == N); for (usize i = 0 ; const auto& row : data) { assert(row.size() == N); for (usize j = 0 ; const auto& x : row) m_data[i*N+j++]=x; i++; } } constexpr std::span operator[](usize i) & { return std::span{m_data.data()+i*N,N}; } constexpr std::span operator[](usize i) const& { return std::span{m_data.data()+i*N,N}; } constexpr usize size() const noexcept { return N; } static constexpr Element zero() { return ConstantSquareMatrix(); } static constexpr Element identity() { auto res = ConstantSquareMatrix(); for (usize i = 0 ; i < N ; i++) res[i][i] = M::identity(); return res; } static constexpr Element operation(const Element& lhs,const Element& rhs) { Element res = zero(); for (usize i = 0 ; i < N ; i++) { for (usize k = 0 ; k < N ; k++) { const T& x = lhs[i][k]; for (usize j = 0 ; j < N ; j++) res[i][j] = A::operation(res[i][j],M::operation(x,rhs[k][j])); } } return res; } static constexpr std::array leftAction(const Element& mat,const std::array& vec) { std::array res; for (usize i = 0 ; i < N ; i++) { res[i] = A::identity(); for (usize j = 0 ; j < N ; j++) res[i] = A::operation(res[i],M::operation(mat[i][j],vec[j])); } return res; } private: std::array m_data; }; } // namespace zawa namespace zawa { template class AdditiveGroup { public: using Element = T; static constexpr T identity() noexcept { return T{}; } static constexpr T operation(T l,T r) noexcept { return l + r; } static constexpr T inverse(T v) noexcept { return -v; } template static constexpr T power(T v,U exp) noexcept { return v * static_cast(exp); } }; } // namespace zawa namespace zawa { namespace internal { template struct Multiplication { using Element = T; static constexpr Element identity() { return static_cast(1); } static constexpr Element operation(const Element& lhs, const Element& rhs) { return lhs * rhs; } static constexpr Element inverse(const Element& value) { return identity() / value; } }; } // namespace internal template struct UsualRing { using Element = T; using Addition = AdditiveGroup; using Multiplication = typename internal::Multiplication; }; } // namespace zawa namespace zawa {} using namespace zawa; // #include "atcoder/modint" // using mint = atcoder::modint998244353; // #include // #include // #include // #include // #include // #include // #include // #include // #include // #include // #include // #include // #include // #pragma GCC target("avx2") // #pragma GCC optimize("O3") // #pragma GCC optimize("unroll-loops") using namespace std; template ostream& operator<<(ostream& os, const pair& p) { os << '(' << p.first << ',' << p.second << ')'; return os; } template ostream& operator<<(ostream& os, const vector& v) { for (int i = 0 ; i < ssize(v) ; i++) os << v[i] << (i + 1 == ssize(v) ? "" : " "); return os; } /* * */ using M=ConstantSquareMatrix,4>; // 0...今0 // 1...今1 // 2...全部の1 // 3...定数項 M gen(char c,int t) { M res=M::zero(); res[2][2]=1; res[3][3]=1; res[3][t]++; if (t) res[3][2]++; if (c!='_') for (int i : {0,1}) { int to; if (c=='+') to=i|t; else if (c=='*') to=i&t; else if (c=='^') to=i^t; else assert(0); res[i][to]++; if (to) res[i][2]++; } return res; } int main() { cin.tie(0); cout.tie(0); ios::sync_with_stdio(0); cout << fixed << setprecision(20); #if !defined DEBUG int N,Q; cin >> N >> Q; string S; cin >> S; S.insert(S.begin(),'_'); vector A; A.reserve(N/2); for (int i = 1 ; i < ssize(S) ; i += 2) A.push_back(gen(S[i-1],S[i]=='T')); SegmentTree seg(move(A)); while (Q--) { int l,r; cin >> l >> r; l/=2; r=(r+1)/2; auto pd=seg.product(l,r); cout << pd[3][2] << '\n'; } #else mt19937_64 mt{random_device{}()}; for (int testcase = 0 ; ; ) { cerr << "----------" << ++testcase << "----------" << endl; auto a = solve(), b = naive(); if (a != b) { // print testcase cerr << "you: " << a << endl; cout << "correct: " << b << endl; exit(0); } } #endif }