From 811ab4213a25cbeafd16d968fd18b007c4f864c1 Mon Sep 17 00:00:00 2001 From: hitonanode <32937551+hitonanode@users.noreply.github.com> Date: Sun, 24 Aug 2025 23:32:38 +0900 Subject: [PATCH] fix segtrees --- segmenttree/acl_beats.hpp | 10 ++-- segmenttree/acl_lazysegtree.hpp | 80 +++++++++++++++++--------- segmenttree/acl_segtree.hpp | 38 ++++++++---- segmenttree/acl_segtree.md | 22 +++++++ segmenttree/binary_indexed_tree_2d.hpp | 3 +- 5 files changed, 107 insertions(+), 46 deletions(-) create mode 100644 segmenttree/acl_segtree.md diff --git a/segmenttree/acl_beats.hpp b/segmenttree/acl_beats.hpp index 4396b131..ef5b9dfc 100644 --- a/segmenttree/acl_beats.hpp +++ b/segmenttree/acl_beats.hpp @@ -1,12 +1,14 @@ #pragma once #include "acl_lazysegtree.hpp" -template +#include +#include + +template class segtree_beats : public atcoder::lazy_segtree { using Base = atcoder::lazy_segtree; using Base::lazy_segtree; - void all_apply(int k, F f) const override { + void all_apply(int k, F f) override { Base::d[k] = mapping(f, Base::d[k]); if (k < Base::size) { Base::lz[k] = composition(f, Base::lz[k]); @@ -16,8 +18,6 @@ class segtree_beats : public atcoder::lazy_segtree - template inline Num second_lowest(Num a, Num a2, Num c, Num c2) noexcept { assert(a <= a2); // a < a2 or a == a2 == INF assert(c <= c2); // c < c2 or c == c2 == -INF diff --git a/segmenttree/acl_lazysegtree.hpp b/segmenttree/acl_lazysegtree.hpp index fd9b0b19..e5e76430 100644 --- a/segmenttree/acl_lazysegtree.hpp +++ b/segmenttree/acl_lazysegtree.hpp @@ -5,21 +5,32 @@ #include #endif +#if __cplusplus >= 202002L +#include +#endif + namespace atcoder { namespace internal { -// @param n `0 <= n` -// @return minimum non-negative `x` s.t. `n <= 2**x` -int ceil_pow2(int n) { - int x = 0; - while ((1U << x) < (unsigned int)(n)) x++; +#if __cplusplus >= 202002L + +using std::bit_ceil; + +#else + +// @return same with std::bit::bit_ceil +unsigned int bit_ceil(unsigned int n) { + unsigned int x = 1; + while (x < (unsigned int)(n)) x *= 2; return x; } +#endif + // @param n `1 <= n` -// @return minimum non-negative `x` s.t. `(n & (1 << x)) != 0` -int bsf(unsigned int n) { +// @return same with std::bit::countr_zero +int countr_zero(unsigned int n) { #ifdef _MSC_VER unsigned long index; _BitScanForward(&index, n); @@ -29,6 +40,14 @@ int bsf(unsigned int n) { #endif } +// @param n `1 <= n` +// @return same with std::bit::countr_zero +constexpr int countr_zero_constexpr(unsigned int n) { + int x = 0; + while (!(n & (1 << x))) x++; + return x; +} + } // namespace internal } // namespace atcoder @@ -37,24 +56,31 @@ int bsf(unsigned int n) { #ifndef ATCODER_LAZYSEGTREE_HPP #define ATCODER_LAZYSEGTREE_HPP 1 -#include #include -#include +#include #include -// #include "atcoder/internal_bit" +#include "atcoder/internal_bit" namespace atcoder { -template +template struct lazy_segtree { + static_assert(std::is_convertible_v>, + "op must work as S(S, S)"); + static_assert(std::is_convertible_v>, "e must work as S()"); + static_assert(std::is_convertible_v>, + "mapping must work as S(F, S)"); + static_assert(std::is_convertible_v>, + "composition must work as F(F, F)"); + static_assert(std::is_convertible_v>, "id must work as F()"); + public: lazy_segtree() : lazy_segtree(0) {} explicit lazy_segtree(int n) : lazy_segtree(std::vector(n, e())) {} explicit lazy_segtree(const std::vector &v) : _n(int(v.size())) { - log = internal::ceil_pow2(_n); - size = 1 << log; + size = (int)internal::bit_ceil((unsigned int)(_n)); + log = internal::countr_zero((unsigned int)size); d = std::vector(2 * size, e()); lz = std::vector(size, id()); for (int i = 0; i < _n; i++) d[size + i] = v[i]; @@ -69,14 +95,14 @@ struct lazy_segtree { for (int i = 1; i <= log; i++) update(p >> i); } - S get(int p) const { + S get(int p) { assert(0 <= p && p < _n); p += size; for (int i = log; i >= 1; i--) push(p >> i); return d[p]; } - S prod(int l, int r) const { + S prod(int l, int r) { assert(0 <= l && l <= r && r <= _n); if (l == r) return e(); @@ -99,7 +125,7 @@ struct lazy_segtree { return op(sml, smr); } - S all_prod() const { return d[1]; } + S all_prod() { return d[1]; } void apply(int p, F f) { assert(0 <= p && p < _n); @@ -138,10 +164,10 @@ struct lazy_segtree { } } - template int max_right(int l) const { + template int max_right(int l) { return max_right(l, [](S x) { return g(x); }); } - template int max_right(int l, G g) const { + template int max_right(int l, G g) { assert(0 <= l && l <= _n); assert(g(e())); if (l == _n) return _n; @@ -167,10 +193,10 @@ struct lazy_segtree { return _n; } - template int min_left(int r) const { + template int min_left(int r) { return min_left(r, [](S x) { return g(x); }); } - template int min_left(int r, G g) const { + template int min_left(int r, G g) { assert(0 <= r && r <= _n); assert(g(e())); if (r == 0) return 0; @@ -198,15 +224,15 @@ struct lazy_segtree { protected: int _n, size, log; - mutable std::vector d; - mutable std::vector lz; + std::vector d; + std::vector lz; - void update(int k) const { d[k] = op(d[2 * k], d[2 * k + 1]); } - virtual void all_apply(int k, F f) const { + void update(int k) { d[k] = op(d[2 * k], d[2 * k + 1]); } + virtual void all_apply(int k, F f) { d[k] = mapping(f, d[k]); if (k < size) lz[k] = composition(f, lz[k]); } - void push(int k) const { + void push(int k) { all_apply(2 * k, lz[k]); all_apply(2 * k + 1, lz[k]); lz[k] = id(); @@ -214,7 +240,7 @@ struct lazy_segtree { }; } // namespace atcoder #endif // ATCODER_LAZYSEGTREE_HPP -// Reference: https://atcoder.github.io/ac-library/document_ja/lazysegtree.html +// Reference: https://atcoder.github.io/ac-library/production/document_ja/lazysegtree.html // https://betrue12.hateblo.jp/entry/2020/09/22/194541 // https://betrue12.hateblo.jp/entry/2020/09/23/005940 /* diff --git a/segmenttree/acl_segtree.hpp b/segmenttree/acl_segtree.hpp index 5d149965..7f4fe0a3 100644 --- a/segmenttree/acl_segtree.hpp +++ b/segmenttree/acl_segtree.hpp @@ -5,21 +5,32 @@ #include #endif +#if __cplusplus >= 202002L +#include +#endif + namespace atcoder { namespace internal { -// @param n `0 <= n` -// @return minimum non-negative `x` s.t. `n <= 2**x` -int ceil_pow2(int n) { - int x = 0; - while ((1U << x) < (unsigned int)(n)) x++; +#if __cplusplus >= 202002L + +using std::bit_ceil; + +#else + +// @return same with std::bit::bit_ceil +unsigned int bit_ceil(unsigned int n) { + unsigned int x = 1; + while (x < (unsigned int)(n)) x *= 2; return x; } +#endif + // @param n `1 <= n` -// @return minimum non-negative `x` s.t. `(n & (1 << x)) != 0` -int bsf(unsigned int n) { +// @return same with std::bit::countr_zero +int countr_zero(unsigned int n) { #ifdef _MSC_VER unsigned long index; _BitScanForward(&index, n); @@ -38,21 +49,24 @@ int bsf(unsigned int n) { #ifndef ATCODER_SEGTREE_HPP #define ATCODER_SEGTREE_HPP 1 -#include #include +#include #include // #include "atcoder/internal_bit" namespace atcoder { +template struct segtree { + static_assert(std::is_convertible_v>, + "op must work as S(S, S)"); + static_assert(std::is_convertible_v>, "e must work as S()"); -template struct segtree { public: segtree() : segtree(0) {} explicit segtree(int n) : segtree(std::vector(n, e())) {} explicit segtree(const std::vector &v) : _n(int(v.size())) { - log = internal::ceil_pow2(_n); - size = 1 << log; + size = (int)internal::bit_ceil((unsigned int)(_n)); + log = internal::countr_zero((unsigned int)size); d = std::vector(2 * size, e()); for (int i = 0; i < _n; i++) d[size + i] = v[i]; for (int i = size - 1; i >= 1; i--) { update(i); } @@ -152,7 +166,7 @@ template struct segtree { #endif // ATCODER_SEGTREE_HPP -// Reference: https://atcoder.github.io/ac-library/document_ja/segtree.html +// Reference: https://atcoder.github.io/ac-library/production/document_ja/segtree.html /* usage: struct S { long long su; diff --git a/segmenttree/acl_segtree.md b/segmenttree/acl_segtree.md new file mode 100644 index 00000000..9f3df918 --- /dev/null +++ b/segmenttree/acl_segtree.md @@ -0,0 +1,22 @@ +--- +title: Segtree (based on atcoder::segtree) +documentation_of: ./acl_segtree.hpp +--- + +ACL-based segtree + +## Example + +```cpp +struct S {}; +S op(S l, S r) { + return {}; +} +S e() { return {}; }; +vector A; +atcoder::segtree seg(A); +``` + +## Link + +- [ACL reference](https://atcoder.github.io/ac-library/production/document_ja/segtree.html) diff --git a/segmenttree/binary_indexed_tree_2d.hpp b/segmenttree/binary_indexed_tree_2d.hpp index 98af7ace..d2e4b4aa 100644 --- a/segmenttree/binary_indexed_tree_2d.hpp +++ b/segmenttree/binary_indexed_tree_2d.hpp @@ -1,8 +1,7 @@ #pragma once #include -// CUT begin -// 2-dimentional 1-indexed BIT (i : [1, lenX][1, lenY]) +// 2-dimensional 1-indexed BIT (i : [1, lenX][1, lenY]) template struct BIT_2D { std::array val; constexpr static int M = lenY + 1;