|
| 1 | +--- |
| 2 | +data: |
| 3 | + _extendedDependsOn: |
| 4 | + - icon: ':heavy_check_mark:' |
| 5 | + path: weilycoder/ds/segment_tree.hpp |
| 6 | + title: Segment Tree Data Structure |
| 7 | + _extendedRequiredBy: [] |
| 8 | + _extendedVerifiedWith: [] |
| 9 | + _isVerificationFailed: false |
| 10 | + _pathExtension: cpp |
| 11 | + _verificationStatusIcon: ':heavy_check_mark:' |
| 12 | + attributes: |
| 13 | + '*NOT_SPECIAL_COMMENTS*': '' |
| 14 | + PROBLEM: https://judge.yosupo.jp/problem/point_set_range_composite |
| 15 | + links: |
| 16 | + - https://judge.yosupo.jp/problem/point_set_range_composite |
| 17 | + bundledCode: "#line 1 \"test/point_set_range_composite2.test.cpp\"\n#define PROBLEM\ |
| 18 | + \ \"https://judge.yosupo.jp/problem/point_set_range_composite\"\n\n#line 1 \"\ |
| 19 | + weilycoder/ds/segment_tree.hpp\"\n\n\n\n/**\n * @file segment_tree.hpp\n * @brief\ |
| 20 | + \ Segment Tree Data Structure\n */\n\n#include <cstddef>\n#include <limits>\n\ |
| 21 | + #include <stdexcept>\n#include <vector>\n\nnamespace weilycoder {\ntemplate <typename\ |
| 22 | + \ _Monoid, typename _ptr_t = size_t> struct SegmentTreeHeapSon {\nprotected:\n\ |
| 23 | + \ using T = typename _Monoid::value_type;\n using ptr_t = _ptr_t;\n using Monoid\ |
| 24 | + \ = _Monoid;\n static constexpr ptr_t null = std::numeric_limits<ptr_t>::max();\n\ |
| 25 | + \nprivate:\n ptr_t st, ed;\n std::vector<T> data;\n\n void init(ptr_t node,\ |
| 26 | + \ ptr_t l, ptr_t r, const std::vector<T> &arr) {\n if (r - l == 1) {\n \ |
| 27 | + \ data[node] = arr[l];\n } else {\n ptr_t mid = l + ((r - l) >> 1);\n\ |
| 28 | + \ init(node * 2 + 1, l, mid, arr), init(node * 2 + 2, mid, r, arr);\n \ |
| 29 | + \ pushup(node);\n }\n }\n\nprotected:\n ptr_t get_st() const { return st;\ |
| 30 | + \ }\n ptr_t get_ed() const { return ed; }\n\n T &get_value(ptr_t node) { return\ |
| 31 | + \ data[node]; }\n const T &get_value(ptr_t node) const { return data[node]; }\n\ |
| 32 | + \n ptr_t get_lc(ptr_t node) const { return node * 2 + 1; }\n ptr_t get_rc(ptr_t\ |
| 33 | + \ node) const { return node * 2 + 2; }\n\n void pushdown(ptr_t node) const {}\n\ |
| 34 | + \ void pushup(ptr_t node) {\n data[node] = Monoid::operation(data[get_lc(node)],\ |
| 35 | + \ data[get_rc(node)]);\n }\n\n explicit SegmentTreeHeapSon(ptr_t size) : st(0),\ |
| 36 | + \ ed(size) {\n data.resize(size * 4, Monoid::identity());\n }\n\n explicit\ |
| 37 | + \ SegmentTreeHeapSon(ptr_t st, ptr_t ed) : st(st), ed(ed) {\n data.resize((ed\ |
| 38 | + \ - st) * 4, Monoid::identity());\n }\n\n explicit SegmentTreeHeapSon(const\ |
| 39 | + \ std::vector<T> &arr)\n : st(0), ed(static_cast<ptr_t>(arr.size())) {\n\ |
| 40 | + \ data.resize(arr.size() * 4, Monoid::identity());\n init(0, st, ed, arr);\n\ |
| 41 | + \ }\n};\n\n/**\n * @brief Segment Tree Base Class that stores child pointers\n\ |
| 42 | + \ * @tparam _Monoid The monoid defining the operation and identity\n * @tparam\ |
| 43 | + \ _ptr_t The pointer type used for indexing nodes (default: size_t)\n */\ntemplate\ |
| 44 | + \ <typename _Monoid, typename _ptr_t = size_t> struct SegmentTreeStoreSon {\n\ |
| 45 | + protected:\n using T = typename _Monoid::value_type;\n using ptr_t = _ptr_t;\n\ |
| 46 | + \ using Monoid = _Monoid;\n static constexpr ptr_t null = std::numeric_limits<ptr_t>::max();\n\ |
| 47 | + \nprivate:\n struct Node {\n T value;\n ptr_t left, right;\n\n Node()\ |
| 48 | + \ : value(Monoid::identity()), left(null), right(null) {}\n };\n\n ptr_t st,\ |
| 49 | + \ ed;\n std::vector<Node> data;\n\n ptr_t build(ptr_t l, ptr_t r) {\n ptr_t\ |
| 50 | + \ node = data.size();\n data.emplace_back();\n if (r - l > 1) {\n ptr_t\ |
| 51 | + \ mid = l + ((r - l) >> 1);\n ptr_t left = build(l, mid), right = build(mid,\ |
| 52 | + \ r);\n data[node].left = left, data[node].right = right;\n }\n return\ |
| 53 | + \ node;\n }\n\n ptr_t init(ptr_t l, ptr_t r, const std::vector<T> &arr) {\n\ |
| 54 | + \ ptr_t node = data.size();\n data.emplace_back();\n if (r - l == 1)\ |
| 55 | + \ {\n data[node].value = arr[l];\n } else {\n ptr_t mid = l + ((r\ |
| 56 | + \ - l) >> 1);\n ptr_t left = init(l, mid, arr), right = init(mid, r, arr);\n\ |
| 57 | + \ data[node].left = left, data[node].right = right;\n pushup(node);\n\ |
| 58 | + \ }\n return node;\n }\n\nprotected:\n ptr_t get_st() const { return st;\ |
| 59 | + \ }\n ptr_t get_ed() const { return ed; }\n\n T &get_value(ptr_t node) { return\ |
| 60 | + \ data[node].value; }\n const T &get_value(ptr_t node) const { return data[node].value;\ |
| 61 | + \ }\n\n ptr_t get_lc(ptr_t node) const { return data[node].left; }\n ptr_t get_rc(ptr_t\ |
| 62 | + \ node) const { return data[node].right; }\n\n void pushdown(ptr_t node) const\ |
| 63 | + \ {}\n void pushup(ptr_t node) {\n data[node].value =\n Monoid::operation(data[data[node].left].value,\ |
| 64 | + \ data[data[node].right].value);\n }\n\n explicit SegmentTreeStoreSon(ptr_t\ |
| 65 | + \ size) : st(0), ed(size) {\n data.reserve(size * 2 - 1);\n build(st, ed);\n\ |
| 66 | + \ }\n\n explicit SegmentTreeStoreSon(ptr_t st, ptr_t ed) : st(st), ed(ed) {\n\ |
| 67 | + \ data.reserve((ed - st) * 2 - 1);\n build(st, ed);\n }\n\n explicit SegmentTreeStoreSon(const\ |
| 68 | + \ std::vector<T> &arr)\n : st(0), ed(static_cast<ptr_t>(arr.size())) {\n\ |
| 69 | + \ data.reserve(arr.size() * 2 - 1);\n init(0, arr.size(), arr);\n }\n};\n\ |
| 70 | + \ntemplate <class SegmentBase> struct SegmentTree : private SegmentBase {\n using\ |
| 71 | + \ Monoid = typename SegmentBase::Monoid;\n using ptr_t = typename SegmentBase::ptr_t;\n\ |
| 72 | + \ using T = typename Monoid::value_type;\n static constexpr ptr_t null = SegmentBase::null;\n\ |
| 73 | + \nprivate:\n void point_set(ptr_t node, ptr_t l, ptr_t r, ptr_t pos, const T\ |
| 74 | + \ &val) {\n if (r - l == 1)\n SegmentBase::get_value(node) = val;\n \ |
| 75 | + \ else {\n ptr_t mid = l + ((r - l) >> 1);\n if (pos < mid)\n \ |
| 76 | + \ point_set(SegmentBase::get_lc(node), l, mid, pos, val);\n else\n \ |
| 77 | + \ point_set(SegmentBase::get_rc(node), mid, r, pos, val);\n SegmentBase::pushup(node);\n\ |
| 78 | + \ }\n }\n\n void point_update(ptr_t node, ptr_t l, ptr_t r, ptr_t pos, const\ |
| 79 | + \ T &val) {\n if (r - l == 1)\n SegmentBase::get_value(node) =\n \ |
| 80 | + \ Monoid::operation(SegmentBase::get_value(node), val);\n else {\n \ |
| 81 | + \ ptr_t mid = l + ((r - l) >> 1);\n if (pos < mid)\n point_update(SegmentBase::get_lc(node),\ |
| 82 | + \ l, mid, pos, val);\n else\n point_update(SegmentBase::get_rc(node),\ |
| 83 | + \ mid, r, pos, val);\n SegmentBase::pushup(node);\n }\n }\n\n T point_query(ptr_t\ |
| 84 | + \ node, ptr_t l, ptr_t r, ptr_t pos) const {\n if (r - l == 1)\n return\ |
| 85 | + \ SegmentBase::get_value(node);\n ptr_t mid = l + ((r - l) >> 1);\n if (pos\ |
| 86 | + \ < mid)\n return point_query(SegmentBase::get_lc(node), l, mid, pos);\n\ |
| 87 | + \ else\n return point_query(SegmentBase::get_rc(node), mid, r, pos);\n\ |
| 88 | + \ }\n\n T range_query(ptr_t node, ptr_t l, ptr_t r, ptr_t ql, ptr_t qr) const\ |
| 89 | + \ {\n if (ql >= r || qr <= l)\n return Monoid::identity();\n if (ql\ |
| 90 | + \ <= l && r <= qr)\n return SegmentBase::get_value(node);\n ptr_t mid\ |
| 91 | + \ = l + ((r - l) >> 1);\n T left_res = range_query(SegmentBase::get_lc(node),\ |
| 92 | + \ l, mid, ql, qr);\n T right_res = range_query(SegmentBase::get_rc(node), mid,\ |
| 93 | + \ r, ql, qr);\n return Monoid::operation(left_res, right_res);\n }\n\npublic:\n\ |
| 94 | + \ /**\n * @brief Constructs a SegmentTree with given size\n * @param size\ |
| 95 | + \ The size of the array\n */\n explicit SegmentTree(ptr_t size) : SegmentBase(size)\ |
| 96 | + \ {}\n\n /**\n * @brief Constructs a SegmentTree for the range [left, right)\n\ |
| 97 | + \ * @param left The left index (inclusive)\n * @param right The right index\ |
| 98 | + \ (exclusive)\n */\n explicit SegmentTree(ptr_t left, ptr_t right) : SegmentBase(left,\ |
| 99 | + \ right) {}\n\n /**\n * @brief Constructs a SegmentTree from an initial array\n\ |
| 100 | + \ * @param arr Initial array of elements\n */\n explicit SegmentTree(const\ |
| 101 | + \ std::vector<T> &arr) : SegmentBase(arr) {}\n\n /**\n * @brief Sets the value\ |
| 102 | + \ at position pos to val\n * @param pos The position to update\n * @param\ |
| 103 | + \ val The new value\n */\n void point_set(ptr_t pos, const T &val) {\n if\ |
| 104 | + \ (pos < get_st() || pos >= get_ed())\n throw std::out_of_range(\"SegmentTree::point_set:\ |
| 105 | + \ position out of range\");\n point_set(0, get_st(), get_ed(), pos, val);\n\ |
| 106 | + \ }\n\n /**\n * @brief Updates the value at position pos by applying the monoid\ |
| 107 | + \ operation with val\n * @param pos The position to update\n * @param val\ |
| 108 | + \ The value to combine\n */\n void point_update(ptr_t pos, const T &val) {\n\ |
| 109 | + \ if (pos < get_st() || pos >= get_ed())\n throw std::out_of_range(\"\ |
| 110 | + SegmentTree::point_update: position out of range\");\n point_update(0, get_st(),\ |
| 111 | + \ get_ed(), pos, val);\n }\n\n /**\n * @brief Queries the value at position\ |
| 112 | + \ pos\n * @param pos The position to query\n * @return The value at position\ |
| 113 | + \ pos\n */\n T point_query(ptr_t pos) const {\n if (pos < get_st() || pos\ |
| 114 | + \ >= get_ed())\n throw std::out_of_range(\"SegmentTree::point_query: position\ |
| 115 | + \ out of range\");\n return point_query(0, get_st(), get_ed(), pos);\n }\n\ |
| 116 | + \n /**\n * @brief Queries the range [left, right)\n * @param left The left\ |
| 117 | + \ index (inclusive)\n * @param right The right index (exclusive)\n * @return\ |
| 118 | + \ The result of the monoid operation over the range\n */\n T range_query(ptr_t\ |
| 119 | + \ left, ptr_t right) const {\n if (left < get_st() || right > get_ed() || left\ |
| 120 | + \ > right)\n throw std::out_of_range(\"SegmentTree::range_query: range out\ |
| 121 | + \ of bounds\");\n return range_query(0, get_st(), get_ed(), left, right);\n\ |
| 122 | + \ }\n\n ptr_t get_st() const { return SegmentBase::get_st(); }\n ptr_t get_ed()\ |
| 123 | + \ const { return SegmentBase::get_ed(); }\n};\n} // namespace weilycoder\n\n\n\ |
| 124 | + #line 4 \"test/point_set_range_composite2.test.cpp\"\n#include <cstdint>\n#include\ |
| 125 | + \ <iostream>\n#line 7 \"test/point_set_range_composite2.test.cpp\"\nusing namespace\ |
| 126 | + \ std;\nusing namespace weilycoder;\n\nstatic constexpr uint64_t mod = 998244353;\n\ |
| 127 | + \nstruct AffineMonoid {\n using value_type = pair<uint64_t, uint64_t>; // (a,\ |
| 128 | + \ b) represents f(x) = a * x + b\n\n static value_type identity() { return {1,\ |
| 129 | + \ 0}; }\n static value_type operation(const value_type &f, const value_type &g)\ |
| 130 | + \ {\n return {(g.first * f.first) % mod, (g.first * f.second + g.second) %\ |
| 131 | + \ mod};\n }\n\n static uint64_t affine(const value_type &f, uint64_t x) {\n\ |
| 132 | + \ return (f.first * x + f.second) % mod;\n }\n};\n\nint main() {\n cin.tie(nullptr)->sync_with_stdio(false);\n\ |
| 133 | + \ cin.exceptions(cin.badbit | cin.failbit);\n size_t n, q;\n cin >> n >> q;\n\ |
| 134 | + \n vector<pair<uint64_t, uint64_t>> affines;\n affines.reserve(n);\n for (size_t\ |
| 135 | + \ i = 0; i < n; ++i) {\n uint64_t a, b;\n cin >> a >> b;\n affines.emplace_back(a,\ |
| 136 | + \ b);\n }\n\n SegmentTree<SegmentTreeStoreSon<AffineMonoid>> sgt(affines);\n\ |
| 137 | + \ while (q--) {\n size_t op;\n cin >> op;\n if (op == 0) {\n size_t\ |
| 138 | + \ p;\n uint64_t c, d;\n cin >> p >> c >> d;\n sgt.point_set(p,\ |
| 139 | + \ {c, d});\n } else {\n size_t l, r;\n uint64_t x;\n cin >>\ |
| 140 | + \ l >> r >> x;\n auto func = sgt.range_query(l, r);\n cout << AffineMonoid::affine(func,\ |
| 141 | + \ x) << '\\n';\n }\n }\n return 0;\n}\n" |
| 142 | + code: "#define PROBLEM \"https://judge.yosupo.jp/problem/point_set_range_composite\"\ |
| 143 | + \n\n#include \"../weilycoder/ds/segment_tree.hpp\"\n#include <cstdint>\n#include\ |
| 144 | + \ <iostream>\n#include <vector>\nusing namespace std;\nusing namespace weilycoder;\n\ |
| 145 | + \nstatic constexpr uint64_t mod = 998244353;\n\nstruct AffineMonoid {\n using\ |
| 146 | + \ value_type = pair<uint64_t, uint64_t>; // (a, b) represents f(x) = a * x + b\n\ |
| 147 | + \n static value_type identity() { return {1, 0}; }\n static value_type operation(const\ |
| 148 | + \ value_type &f, const value_type &g) {\n return {(g.first * f.first) % mod,\ |
| 149 | + \ (g.first * f.second + g.second) % mod};\n }\n\n static uint64_t affine(const\ |
| 150 | + \ value_type &f, uint64_t x) {\n return (f.first * x + f.second) % mod;\n \ |
| 151 | + \ }\n};\n\nint main() {\n cin.tie(nullptr)->sync_with_stdio(false);\n cin.exceptions(cin.badbit\ |
| 152 | + \ | cin.failbit);\n size_t n, q;\n cin >> n >> q;\n\n vector<pair<uint64_t,\ |
| 153 | + \ uint64_t>> affines;\n affines.reserve(n);\n for (size_t i = 0; i < n; ++i)\ |
| 154 | + \ {\n uint64_t a, b;\n cin >> a >> b;\n affines.emplace_back(a, b);\n\ |
| 155 | + \ }\n\n SegmentTree<SegmentTreeStoreSon<AffineMonoid>> sgt(affines);\n while\ |
| 156 | + \ (q--) {\n size_t op;\n cin >> op;\n if (op == 0) {\n size_t p;\n\ |
| 157 | + \ uint64_t c, d;\n cin >> p >> c >> d;\n sgt.point_set(p, {c, d});\n\ |
| 158 | + \ } else {\n size_t l, r;\n uint64_t x;\n cin >> l >> r >> x;\n\ |
| 159 | + \ auto func = sgt.range_query(l, r);\n cout << AffineMonoid::affine(func,\ |
| 160 | + \ x) << '\\n';\n }\n }\n return 0;\n}" |
| 161 | + dependsOn: |
| 162 | + - weilycoder/ds/segment_tree.hpp |
| 163 | + isVerificationFile: true |
| 164 | + path: test/point_set_range_composite2.test.cpp |
| 165 | + requiredBy: [] |
| 166 | + timestamp: '2025-11-01 13:01:38+08:00' |
| 167 | + verificationStatus: TEST_ACCEPTED |
| 168 | + verifiedWith: [] |
| 169 | +documentation_of: test/point_set_range_composite2.test.cpp |
| 170 | +layout: document |
| 171 | +redirect_from: |
| 172 | +- /verify/test/point_set_range_composite2.test.cpp |
| 173 | +- /verify/test/point_set_range_composite2.test.cpp.html |
| 174 | +title: test/point_set_range_composite2.test.cpp |
| 175 | +--- |
0 commit comments