Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
tpl_segment_tree.H
Go to the documentation of this file.
1
2/*
3 Aleph_w
4
5 Data structures & Algorithms
6 version 2.0.0b
7 https://github.com/lrleon/Aleph-w
8
9 This file is part of Aleph-w library
10
11 Copyright (c) 2002-2026 Leandro Rabindranath Leon
12
13 Permission is hereby granted, free of charge, to any person obtaining a copy
14 of this software and associated documentation files (the "Software"), to deal
15 in the Software without restriction, including without limitation the rights
16 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17 copies of the Software, and to permit persons to whom the Software is
18 furnished to do so, subject to the following conditions:
19
20 The above copyright notice and this permission notice shall be included in all
21 copies or substantial portions of the Software.
22
23 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29 SOFTWARE.
30*/
31
32
62# ifndef TPL_SEGMENT_TREE_H
63# define TPL_SEGMENT_TREE_H
64
65# include <cassert>
66# include <concepts>
67# include <algorithm>
68# include <initializer_list>
69# include <limits>
70# include <type_traits>
71# include <utility>
72# include <vector>
73# include <tpl_array.H>
74# include <tpl_dynList.H>
75# include <ahFunction.H>
76# include <ah-errors.H>
77# include <tpl_sparse_table.H>
78
79namespace Aleph
80{
99 template <typename F, typename T>
101 requires(const F& f, const T& a, const T& b)
102 {
103 { f(a, b) } -> std::convertible_to<T>;
104 };
105
106 // ================================================================
107 // Gen_Segment_Tree — Point update + Range query
108 // ================================================================
109
146 template <typename T, class Op>
147 requires SegmentTreeOp<Op, T>
149 {
150 Array<T> tree; // 1-indexed implicit binary tree
151 size_t n = 0; // number of logical elements
152 T identity; // identity element of the monoid
153 Op op;
154
155 void build(size_t node, const size_t start, const size_t end)
156 {
157 if (start == end)
158 return;
159
160 const size_t mid = start + (end - start) / 2;
161 build(2 * node, start, mid);
162 build(2 * node + 1, mid + 1, end);
163 tree(node) = op(tree(2 * node), tree(2 * node + 1));
164 }
165
166 void update_impl(size_t node, const size_t start, const size_t end,
167 const size_t idx, const T & delta)
168 {
169 if (start == end)
170 {
171 tree(node) = op(tree(node), delta);
172 return;
173 }
174
175 if (const size_t mid = start + (end - start) / 2; idx <= mid)
176 update_impl(2 * node, start, mid, idx, delta);
177 else
178 update_impl(2 * node + 1, mid + 1, end, idx, delta);
179
180 tree(node) = op(tree(2 * node), tree(2 * node + 1));
181 }
182
183 void set_impl(size_t node, const size_t start, const size_t end,
184 const size_t idx, const T & val)
185 {
186 if (start == end)
187 {
188 tree(node) = val;
189 return;
190 }
191
192 if (const size_t mid = start + (end - start) / 2; idx <= mid)
193 set_impl(2 * node, start, mid, idx, val);
194 else
195 set_impl(2 * node + 1, mid + 1, end, idx, val);
196
197 tree(node) = op(tree(2 * node), tree(2 * node + 1));
198 }
199
200 T query_impl(size_t node, const size_t start, const size_t end,
201 const size_t l, const size_t r) const
202 {
203 if (r < start || end < l)
204 return identity;
205
206 if (l <= start and end <= r)
207 return tree(node);
208
209 const size_t mid = start + (end - start) / 2;
210 return op(query_impl(2 * node, start, mid, l, r),
211 query_impl(2 * node + 1, mid + 1, end, l, r));
212 }
213
214 template <class Getter>
216 {
217 // Place values in leaves via recursive descent
218 fill_leaves_recursive(1, 0, n - 1, getter);
219
220 // Build internal nodes bottom-up
221 build(1, 0, n - 1);
222 }
223
224 template <class Getter>
225 void fill_leaves_recursive(size_t node, size_t start, size_t end,
226 Getter & getter)
227 {
228 if (start == end)
229 {
230 tree(node) = getter(start);
231 return;
232 }
233
234 const size_t mid = start + (end - start) / 2;
235 fill_leaves_recursive(2 * node, start, mid, getter);
236 fill_leaves_recursive(2 * node + 1, mid + 1, end, getter);
237 }
238
239 template <class AlephIt>
241 {
242 auto tmp = Array<T>::create(n);
243 size_t i = 0;
244 for (; it.has_curr(); it.next_ne())
245 tmp(i++) = it.get_curr();
246
247 auto getter = [&tmp](size_t j) { return tmp(j); };
249 }
250
251 public:
252 using Item_Type = T;
253
262 Gen_Segment_Tree(const size_t num, const T & init_val,
263 const T & id, Op oper = Op())
264 : tree(num == 0 ? 1 : 4 * num, id),
265 n(num), identity(id), op(oper)
266 {
267 if (n > 0)
268 fill_and_build([&init_val](size_t) { return init_val; });
269 }
270
283 Gen_Segment_Tree(std::initializer_list<T> il,
284 const T & id, Op oper = Op())
285 : tree(il.size() == 0 ? 1 : 4 * il.size(), id),
286 n(il.size()), identity(id), op(oper)
287 {
288 if (n > 0)
289 {
290 auto it = il.begin();
291 fill_and_build([&it](size_t) { return *it++; });
292 }
293 }
294
302 const T & id, Op oper = Op())
303 : tree(values.size() == 0 ? 1 : 4 * values.size(), id),
304 n(values.size()), identity(id), op(oper)
305 {
306 if (n > 0)
307 fill_and_build([&values](size_t i) { return values(i); });
308 }
309
316 Gen_Segment_Tree(const std::vector<T> & values,
317 const T & id, Op oper = Op())
318 : tree(values.size() == 0 ? 1 : 4 * values.size(), id),
319 n(values.size()), identity(id), op(oper)
320 {
321 if (n > 0)
322 fill_and_build([&values](size_t i) { return values[i]; });
323 }
324
332 const T & id, Op oper = Op())
333 : tree(values.size() == 0 ? 1 : 4 * values.size(), id),
334 n(values.size()), identity(id), op(oper)
335 {
336 if (n > 0)
337 fill_from_aleph_it(values.get_it());
338 }
339
341
345
347
351
358 void update(const size_t i, const T & delta)
359 {
361 << "Gen_Segment_Tree::update: index " << i << " >= size " << n;
362
363 update_impl(1, 0, n - 1, i, delta);
364 }
365
372 void set(const size_t i, const T & val)
373 {
375 << "Gen_Segment_Tree::set: index " << i << " >= size " << n;
376
377 set_impl(1, 0, n - 1, i, val);
378 }
379
389 T query(const size_t l, const size_t r) const
390 {
392 << "Gen_Segment_Tree::query: r=" << r << " >= n=" << n;
394 << "Gen_Segment_Tree::query: l=" << l << " > r=" << r;
395
396 return query_impl(1, 0, n - 1, l, r);
397 }
398
406 T get(const size_t i) const
407 {
409 << "Gen_Segment_Tree::get: index " << i << " >= size " << n;
410
411 return query_impl(1, 0, n - 1, i, i);
412 }
413
415 [[nodiscard]] constexpr size_t size() const noexcept { return n; }
416
418 [[nodiscard]] constexpr bool is_empty() const noexcept { return n == 0; }
419
425 {
426 auto ret = Array<T>::create(n);
427 for (size_t i = 0; i < n; ++i)
428 ret(i) = get(i);
429 return ret;
430 }
431
433 void swap(Gen_Segment_Tree & other) noexcept(
434 noexcept(std::swap(std::declval<T&>(), std::declval<T&>())) and
435 noexcept(std::swap(std::declval<Op&>(), std::declval<Op&>())))
436 {
437 tree.swap(other.tree);
438 std::swap(n, other.n);
439 std::swap(identity, other.identity);
440 std::swap(op, other.op);
441 }
442 };
443
444
462 template <typename T>
464 : public Gen_Segment_Tree<T, Aleph::plus<T>>
465 {
467
474 Sum_Segment_Tree(const size_t num, const T & init_val = T())
475 : Base(num, init_val, T())
476 {}
477
483 Sum_Segment_Tree(std::initializer_list<T> il)
484 : Base(il, T())
485 {}
486
493 : Base(values, T())
494 {}
495
501 Sum_Segment_Tree(const std::vector<T> & values)
502 : Base(values, T())
503 {}
504
511 : Base(values, T())
512 {}
513 };
514
535 template <std::totally_ordered T>
537 : public Gen_Segment_Tree<T, Min_Op<T>>
538 {
540
547 Min_Segment_Tree(const size_t num,
548 const T & init_val = std::numeric_limits<T>::max())
549 : Base(num, init_val, std::numeric_limits<T>::max())
550 {}
551
557 Min_Segment_Tree(std::initializer_list<T> il)
558 : Base(il, std::numeric_limits<T>::max())
559 {}
560
569
575 Min_Segment_Tree(const std::vector<T> & values)
577 {}
578
587 };
588
610 template <std::totally_ordered T>
612 : public Gen_Segment_Tree<T, Max_Op<T>>
613 {
615
622 Max_Segment_Tree(const size_t num,
623 const T & init_val = std::numeric_limits<T>::lowest())
624 : Base(num, init_val, std::numeric_limits<T>::lowest())
625 {}
626
632 Max_Segment_Tree(std::initializer_list<T> il)
633 : Base(il, std::numeric_limits<T>::lowest())
634 {}
635
642 : Base(values, std::numeric_limits<T>::lowest())
643 {}
644
650 Max_Segment_Tree(const std::vector<T> & values)
651 : Base(values, std::numeric_limits<T>::lowest())
652 {}
653
660 : Base(values, std::numeric_limits<T>::lowest())
661 {}
662 };
663
664
665 // ================================================================
666 // Gen_Lazy_Segment_Tree — Range update + Range query
667 // ================================================================
668
694 template <typename P>
696 std::equality_comparable<typename P::lazy_type> and
697 requires(const P& p,
698 const typename P::value_type& v1,
699 const typename P::value_type& v2,
700 const typename P::lazy_type& lz1,
701 const typename P::lazy_type& lz2,
702 size_t count)
703 {
704 typename P::value_type;
705 typename P::lazy_type;
706 { p.combine(v1, v2) } -> std::convertible_to<typename P::value_type>;
707 { p.apply(v1, lz1, count) } -> std::convertible_to<typename P::value_type>;
708 { p.compose(lz1, lz2) } -> std::convertible_to<typename P::lazy_type>;
709 { p.value_identity() } -> std::convertible_to<typename P::value_type>;
710 { p.lazy_identity() } -> std::convertible_to<typename P::lazy_type>;
711 };
712
726 template <typename T>
728 {
729 using value_type = T;
730 using lazy_type = T;
731
732 static constexpr T combine(const T & a, const T & b) noexcept
733 {
734 return a + b;
735 }
736
737 static constexpr T apply(const T & val, const T & delta,
738 size_t count) noexcept
739 {
740 return val + delta * static_cast<T>(count);
741 }
742
743 static constexpr T compose(const T & old_lazy,
744 const T & new_lazy) noexcept
745 {
746 return old_lazy + new_lazy;
747 }
748
749 static constexpr T value_identity() noexcept { return T(); }
750 static constexpr T lazy_identity() noexcept { return T(); }
751 };
752
766 template <std::totally_ordered T>
768 {
769 using value_type = T;
770 using lazy_type = T;
771
772 static constexpr T combine(const T & a, const T & b) noexcept
773 {
774 return a <= b ? a : b;
775 }
776
777 static constexpr T apply(const T & val, const T & delta,
778 size_t) noexcept
779 {
780 return val + delta;
781 }
782
783 static constexpr T compose(const T & old_lazy,
784 const T & new_lazy) noexcept
785 {
786 return old_lazy + new_lazy;
787 }
788
790 {
791 return std::numeric_limits<T>::max();
792 }
793
794 static constexpr T lazy_identity() noexcept { return T(); }
795 };
796
810 template <std::totally_ordered T>
812 {
813 using value_type = T;
814 using lazy_type = T;
815
816 static constexpr T combine(const T & a, const T & b) noexcept
817 {
818 return a >= b ? a : b;
819 }
820
821 static constexpr T apply(const T & val, const T & delta,
822 size_t) noexcept
823 {
824 return val + delta;
825 }
826
827 static constexpr T compose(const T & old_lazy,
828 const T & new_lazy) noexcept
829 {
830 return old_lazy + new_lazy;
831 }
832
834 {
835 return std::numeric_limits<T>::lowest();
836 }
837
838 static constexpr T lazy_identity() noexcept { return T(); }
839 };
840
860 template <typename T>
862 {
863 using value_type = T;
864 using lazy_type = std::pair<bool, T>;
865
866 static constexpr T combine(const T & a, const T & b) noexcept
867 {
868 return a + b;
869 }
870
871 static constexpr T apply(const T & val, const lazy_type & lz,
872 size_t count) noexcept
873 {
874 return lz.first ? lz.second * static_cast<T>(count) : val;
875 }
876
877 static constexpr lazy_type compose(const lazy_type & old_lz,
878 const lazy_type & new_lz) noexcept
879 {
880 return new_lz.first ? new_lz : old_lz;
881 }
882
883 static constexpr T value_identity() noexcept { return T(); }
884
886 {
887 return {false, T()};
888 }
889 };
890
891
920 template <typename Policy>
923 {
924 public:
925 using value_type = typename Policy::value_type;
926 using lazy_type = typename Policy::lazy_type;
928
929 private:
932 size_t n = 0;
934
935 void push_down(size_t node, const size_t start, const size_t end) const
936 {
937 if (lazy(node) == pol.lazy_identity())
938 return;
939
940 const size_t mid = start + (end - start) / 2;
941 const size_t left = 2 * node;
942 const size_t right = 2 * node + 1;
943
944 tree(left) = pol.apply(tree(left), lazy(node), mid - start + 1);
945 lazy(left) = pol.compose(lazy(left), lazy(node));
946
947 tree(right) = pol.apply(tree(right), lazy(node), end - mid);
948 lazy(right) = pol.compose(lazy(right), lazy(node));
949
950 lazy(node) = pol.lazy_identity();
951 }
952
953 void build(size_t node, const size_t start, const size_t end)
954 {
955 if (start == end)
956 return;
957
958 const size_t mid = start + (end - start) / 2;
959 build(2 * node, start, mid);
960 build(2 * node + 1, mid + 1, end);
961 tree(node) = pol.combine(tree(2 * node), tree(2 * node + 1));
962 }
963
964 void update_impl(size_t node, const size_t start, const size_t end,
965 const size_t l, const size_t r, const lazy_type & val)
966 {
967 if (r < start or end < l)
968 return;
969
970 if (l <= start and end <= r)
971 {
972 tree(node) = pol.apply(tree(node), val, end - start + 1);
973 lazy(node) = pol.compose(lazy(node), val);
974 return;
975 }
976
977 push_down(node, start, end);
978
979 const size_t mid = start + (end - start) / 2;
980 update_impl(2 * node, start, mid, l, r, val);
981 update_impl(2 * node + 1, mid + 1, end, l, r, val);
982 tree(node) = pol.combine(tree(2 * node), tree(2 * node + 1));
983 }
984
985 value_type query_impl(size_t node, const size_t start, const size_t end,
986 const size_t l, const size_t r) const
987 {
988 if (r < start or end < l)
989 return pol.value_identity();
990
991 if (l <= start and end <= r)
992 return tree(node);
993
994 push_down(node, start, end);
995
996 const size_t mid = start + (end - start) / 2;
997 return pol.combine(
998 query_impl(2 * node, start, mid, l, r),
999 query_impl(2 * node + 1, mid + 1, end, l, r));
1000 }
1001
1002 void set_impl(size_t node, const size_t start, const size_t end,
1003 const size_t idx, const value_type & val)
1004 {
1005 if (start == end)
1006 {
1007 tree(node) = val;
1008 lazy(node) = pol.lazy_identity();
1009 return;
1010 }
1011
1012 push_down(node, start, end);
1013
1014 if (const size_t mid = start + (end - start) / 2; idx <= mid)
1015 set_impl(2 * node, start, mid, idx, val);
1016 else
1017 set_impl(2 * node + 1, mid + 1, end, idx, val);
1018
1019 tree(node) = pol.combine(tree(2 * node), tree(2 * node + 1));
1020 }
1021
1022 template <class Getter>
1024 {
1025 fill_leaves_recursive(1, 0, n - 1, getter);
1026 build(1, 0, n - 1);
1027 }
1028
1029 template <class Getter>
1030 void fill_leaves_recursive(size_t node, size_t start, size_t end,
1031 Getter & getter)
1032 {
1033 if (start == end)
1034 {
1035 tree(node) = getter(start);
1036 return;
1037 }
1038
1039 const size_t mid = start + (end - start) / 2;
1040 fill_leaves_recursive(2 * node, start, mid, getter);
1041 fill_leaves_recursive(2 * node + 1, mid + 1, end, getter);
1042 }
1043
1044 template <class AlephIt>
1046 {
1048 size_t i = 0;
1049 for (; it.has_curr(); it.next_ne())
1050 tmp(i++) = it.get_curr();
1051
1052 auto getter = [&tmp](size_t j) { return tmp(j); };
1054 }
1055
1056 size_t alloc_size() const
1057 {
1058 return n == 0 ? 1 : 4 * n;
1059 }
1060
1061 public:
1063 Gen_Lazy_Segment_Tree(const size_t num,
1064 const value_type & init_val = value_type(),
1065 Policy p = Policy())
1066 : tree(num == 0 ? 1 : 4 * num, p.value_identity()),
1067 lazy(num == 0 ? 1 : 4 * num, p.lazy_identity()),
1068 n(num), pol(p)
1069 {
1070 if (n > 0)
1071 fill_and_build([&init_val](size_t) { return init_val; });
1072 }
1073
1075 Gen_Lazy_Segment_Tree(std::initializer_list<value_type> il,
1076 Policy p = Policy())
1077 : tree(il.size() == 0 ? 1 : 4 * il.size(), p.value_identity()),
1078 lazy(il.size() == 0 ? 1 : 4 * il.size(), p.lazy_identity()),
1079 n(il.size()), pol(p)
1080 {
1081 if (n > 0)
1082 {
1083 auto it = il.begin();
1084 fill_and_build([&it](size_t) { return *it++; });
1085 }
1086 }
1087
1090 Policy p = Policy())
1091 : tree(values.size() == 0 ? 1 : 4 * values.size(), p.value_identity()),
1092 lazy(values.size() == 0 ? 1 : 4 * values.size(), p.lazy_identity()),
1093 n(values.size()), pol(p)
1094 {
1095 if (n > 0)
1096 fill_and_build([&values](size_t i) { return values(i); });
1097 }
1098
1100 Gen_Lazy_Segment_Tree(const std::vector<value_type> & values,
1101 Policy p = Policy())
1102 : tree(values.size() == 0 ? 1 : 4 * values.size(), p.value_identity()),
1103 lazy(values.size() == 0 ? 1 : 4 * values.size(), p.lazy_identity()),
1104 n(values.size()), pol(p)
1105 {
1106 if (n > 0)
1107 fill_and_build([&values](size_t i) { return values[i]; });
1108 }
1109
1112 Policy p = Policy())
1113 : tree(values.size() == 0 ? 1 : 4 * values.size(), p.value_identity()),
1114 lazy(values.size() == 0 ? 1 : 4 * values.size(), p.lazy_identity()),
1115 n(values.size()), pol(p)
1116 {
1117 if (n > 0)
1119 }
1120
1122
1127
1129
1134
1143 void update(const size_t l, const size_t r, const lazy_type & val)
1144 {
1146 << "Gen_Lazy_Segment_Tree::update: r=" << r << " >= n=" << n;
1148 << "Gen_Lazy_Segment_Tree::update: l=" << l << " > r=" << r;
1149
1150 update_impl(1, 0, n - 1, l, r, val);
1151 }
1152
1157 void point_update(const size_t i, const lazy_type & delta)
1158 {
1159 update(i, i, delta);
1160 }
1161
1170 void set(const size_t i, const value_type & val)
1171 {
1173 << "Gen_Lazy_Segment_Tree::set: index " << i << " >= size " << n;
1174
1175 set_impl(1, 0, n - 1, i, val);
1176 }
1177
1189 value_type query(const size_t l, const size_t r) const
1190 {
1192 << "Gen_Lazy_Segment_Tree::query: r=" << r << " >= n=" << n;
1194 << "Gen_Lazy_Segment_Tree::query: l=" << l << " > r=" << r;
1195
1196 return query_impl(1, 0, n - 1, l, r);
1197 }
1198
1203 value_type get(const size_t i) const
1204 {
1205 return query(i, i);
1206 }
1207
1209 [[nodiscard]] constexpr size_t size() const noexcept { return n; }
1210
1212 [[nodiscard]] constexpr bool is_empty() const noexcept { return n == 0; }
1213
1219 {
1221 for (size_t i = 0; i < n; ++i)
1222 ret(i) = get(i);
1223 return ret;
1224 }
1225
1228 noexcept(std::swap(std::declval<Policy&>(), std::declval<Policy&>())))
1229 {
1230 tree.swap(other.tree);
1231 lazy.swap(other.lazy);
1232 std::swap(n, other.n);
1233 std::swap(pol, other.pol);
1234 }
1235 };
1236
1237
1242 template <typename T>
1244 : public Gen_Lazy_Segment_Tree<Add_Sum_Policy<T>>
1245 {
1247 using Base::Base;
1248 };
1249
1258 template <std::totally_ordered T>
1260 : public Gen_Lazy_Segment_Tree<Add_Min_Policy<T>>
1261 {
1263 using Base::Base;
1264 };
1265
1274 template <std::totally_ordered T>
1276 : public Gen_Lazy_Segment_Tree<Add_Max_Policy<T>>
1277 {
1279 using Base::Base;
1280 };
1281
1282
1283 // ================================================================
1284 // Segment_Tree_Beats — Ji Driver's Segment Tree
1285 // ================================================================
1286
1314 template <typename T>
1315 requires std::is_arithmetic_v<T> and std::is_signed_v<T>
1317 {
1324
1326 size_t n = 0;
1327
1328 static constexpr T INF = std::numeric_limits<T>::max();
1329 static constexpr T NEG_INF = std::numeric_limits<T>::lowest();
1330
1331 void init_leaf(size_t node, const T & val)
1332 {
1333 tree(node) = {val, NEG_INF, val, INF, val,
1334 1, 1, INF, NEG_INF};
1335 }
1336
1337 void pull_up(size_t node) const
1338 {
1339 const auto & l = tree(2 * node);
1340 const auto & r = tree(2 * node + 1);
1341
1342 tree(node).sum = l.sum + r.sum;
1343
1344 // max
1345 if (l.max_val > r.max_val)
1346 {
1347 tree(node).max_val = l.max_val;
1348 tree(node).count_max = l.count_max;
1349 tree(node).second_max = std::max(l.second_max, r.max_val);
1350 }
1351 else if (l.max_val < r.max_val)
1352 {
1353 tree(node).max_val = r.max_val;
1354 tree(node).count_max = r.count_max;
1355 tree(node).second_max = std::max(l.max_val, r.second_max);
1356 }
1357 else
1358 {
1359 tree(node).max_val = l.max_val;
1360 tree(node).count_max = l.count_max + r.count_max;
1361 tree(node).second_max = std::max(l.second_max, r.second_max);
1362 }
1363
1364 // min
1365 if (l.min_val < r.min_val)
1366 {
1367 tree(node).min_val = l.min_val;
1368 tree(node).count_min = l.count_min;
1369 tree(node).second_min = std::min(l.second_min, r.min_val);
1370 }
1371 else if (l.min_val > r.min_val)
1372 {
1373 tree(node).min_val = r.min_val;
1374 tree(node).count_min = r.count_min;
1375 tree(node).second_min = std::min(l.min_val, r.second_min);
1376 }
1377 else
1378 {
1379 tree(node).min_val = l.min_val;
1380 tree(node).count_min = l.count_min + r.count_min;
1381 tree(node).second_min = std::min(l.second_min, r.second_min);
1382 }
1383
1384 tree(node).lazy_chmin = INF;
1385 tree(node).lazy_chmax = NEG_INF;
1386 }
1387
1388 void push_chmin_to_child(size_t child, T v) const
1389 {
1390 auto & nd = tree(child);
1391 if (v >= nd.max_val)
1392 return;
1393
1394 nd.sum -= static_cast<T>(nd.count_max) * (nd.max_val - v);
1395
1396 // If all elements in this node are the same value (max == min),
1397 // then reducing max also reduces min
1398 if (nd.min_val == nd.max_val)
1399 nd.min_val = v;
1400 if (nd.second_min == nd.max_val)
1401 nd.second_min = v;
1402
1403 nd.max_val = v;
1404
1405 // Compose with existing lazy tags
1406 nd.lazy_chmin = std::min(nd.lazy_chmin, v);
1407 nd.lazy_chmax = std::min(nd.lazy_chmax, v);
1408 }
1409
1410 void push_chmax_to_child(size_t child, T v) const
1411 {
1412 auto & nd = tree(child);
1413 if (v <= nd.min_val)
1414 return;
1415
1416 nd.sum += static_cast<T>(nd.count_min) * (v - nd.min_val);
1417
1418 // If all elements are the same value, raising min also raises max
1419 if (nd.max_val == nd.min_val)
1420 nd.max_val = v;
1421 if (nd.second_max == nd.min_val)
1422 nd.second_max = v;
1423
1424 nd.min_val = v;
1425
1426 // Compose with existing lazy tags
1427 nd.lazy_chmax = std::max(nd.lazy_chmax, v);
1428 nd.lazy_chmin = std::max(nd.lazy_chmin, v);
1429 }
1430
1431 void push_down(size_t node) const
1432 {
1433 auto & nd = tree(node);
1434
1435 // Push chmax first (raise minimum), then chmin (lower maximum)
1436 // This order is critical for correctness
1437 if (nd.lazy_chmax != NEG_INF)
1438 {
1439 push_chmax_to_child(2 * node, nd.lazy_chmax);
1440 push_chmax_to_child(2 * node + 1, nd.lazy_chmax);
1441 nd.lazy_chmax = NEG_INF;
1442 }
1443
1444 if (nd.lazy_chmin != INF)
1445 {
1446 push_chmin_to_child(2 * node, nd.lazy_chmin);
1447 push_chmin_to_child(2 * node + 1, nd.lazy_chmin);
1448 nd.lazy_chmin = INF;
1449 }
1450 }
1451
1452 void build(size_t node, size_t start, size_t end)
1453 {
1454 if (start == end)
1455 return;
1456
1457 const size_t mid = start + (end - start) / 2;
1458 build(2 * node, start, mid);
1459 build(2 * node + 1, mid + 1, end);
1460 pull_up(node);
1461 }
1462
1463 void chmin_impl(size_t node, const size_t start, const size_t end,
1464 const size_t l, const size_t r, T v)
1465 {
1466 if (r < start or end < l or tree(node).max_val <= v)
1467 return;
1468
1469 if (l <= start and end <= r and tree(node).second_max < v)
1470 {
1471 push_chmin_to_child(node, v);
1472 return;
1473 }
1474
1475 push_down(node);
1476 const size_t mid = start + (end - start) / 2;
1477 chmin_impl(2 * node, start, mid, l, r, v);
1478 chmin_impl(2 * node + 1, mid + 1, end, l, r, v);
1479 pull_up(node);
1480 }
1481
1482 void chmax_impl(size_t node, const size_t start, const size_t end,
1483 const size_t l, const size_t r, T v)
1484 {
1485 if (r < start or end < l or tree(node).min_val >= v)
1486 return;
1487
1488 if (l <= start and end <= r and tree(node).second_min > v)
1489 {
1490 push_chmax_to_child(node, v);
1491 return;
1492 }
1493
1494 push_down(node);
1495 const size_t mid = start + (end - start) / 2;
1496 chmax_impl(2 * node, start, mid, l, r, v);
1497 chmax_impl(2 * node + 1, mid + 1, end, l, r, v);
1498 pull_up(node);
1499 }
1500
1501 T query_sum_impl(size_t node, const size_t start, const size_t end,
1502 const size_t l, const size_t r) const
1503 {
1504 if (r < start or end < l)
1505 return T();
1506
1507 if (l <= start and end <= r)
1508 return tree(node).sum;
1509
1510 push_down(node);
1511 const size_t mid = start + (end - start) / 2;
1512 return query_sum_impl(2 * node, start, mid, l, r) +
1513 query_sum_impl(2 * node + 1, mid + 1, end, l, r);
1514 }
1515
1516 T query_max_impl(size_t node, const size_t start, const size_t end,
1517 const size_t l, const size_t r) const
1518 {
1519 if (r < start or end < l)
1520 return NEG_INF;
1521
1522 if (l <= start and end <= r)
1523 return tree(node).max_val;
1524
1525 push_down(node);
1526 const size_t mid = start + (end - start) / 2;
1527 return std::max(query_max_impl(2 * node, start, mid, l, r),
1528 query_max_impl(2 * node + 1, mid + 1, end, l, r));
1529 }
1530
1531 T query_min_impl(size_t node, const size_t start, const size_t end,
1532 const size_t l, const size_t r) const
1533 {
1534 if (r < start or end < l)
1535 return INF;
1536
1537 if (l <= start and end <= r)
1538 return tree(node).min_val;
1539
1540 push_down(node);
1541 const size_t mid = start + (end - start) / 2;
1542 return std::min(query_min_impl(2 * node, start, mid, l, r),
1543 query_min_impl(2 * node + 1, mid + 1, end, l, r));
1544 }
1545
1546 template <class Getter>
1548 {
1549 fill_leaves_recursive(1, 0, n - 1, getter);
1550 build(1, 0, n - 1);
1551 }
1552
1553 template <class Getter>
1554 void fill_leaves_recursive(const size_t node, size_t start, size_t end,
1555 Getter & getter)
1556 {
1557 if (start == end)
1558 {
1559 init_leaf(node, getter(start));
1560 return;
1561 }
1562
1563 const size_t mid = start + (end - start) / 2;
1564 fill_leaves_recursive(2 * node, start, mid, getter);
1565 fill_leaves_recursive(2 * node + 1, mid + 1, end, getter);
1566 }
1567
1569 {
1570 Node def = {NEG_INF, NEG_INF, INF, INF, T(),
1571 0, 0, INF, NEG_INF};
1572 for (size_t i = 0; i < tree.size(); ++i)
1573 tree(i) = def;
1574 }
1575
1576 public:
1577 using Item_Type = T;
1578
1585 Segment_Tree_Beats(const size_t num, const T & init_val = T())
1586 : tree(Array<Node>::create(num == 0 ? 1 : 4 * num)), n(num)
1587 {
1589 if (n > 0)
1590 fill_and_build([&init_val](size_t) { return init_val; });
1591 }
1592
1598 Segment_Tree_Beats(std::initializer_list<T> il)
1599 : tree(Array<Node>::create(il.size() == 0 ? 1 : 4 * il.size())),
1600 n(il.size())
1601 {
1603 if (n > 0)
1604 {
1605 auto it = il.begin();
1606 fill_and_build([&it](size_t) { return *it++; });
1607 }
1608 }
1609
1616 : tree(Array<Node>::create(values.size() == 0 ? 1 : 4 * values.size())),
1617 n(values.size())
1618 {
1620 if (n > 0)
1621 fill_and_build([&values](size_t i) { return values(i); });
1622 }
1623
1629 Segment_Tree_Beats(const std::vector<T> & values)
1630 : tree(Array<Node>::create(values.size() == 0 ? 1 : 4 * values.size())),
1631 n(values.size())
1632 {
1634 if (n > 0)
1635 fill_and_build([&values](size_t i) { return values[i]; });
1636 }
1637
1644 : tree(Array<Node>::create(values.size() == 0 ? 1 : 4 * values.size())),
1645 n(values.size())
1646 {
1648 if (n > 0)
1649 {
1650 auto tmp = Array<T>::create(n);
1651 size_t i = 0;
1652 for (auto it = values.get_it(); it.has_curr(); it.next_ne())
1653 tmp(i++) = it.get_curr();
1654 fill_and_build([&tmp](size_t j) { return tmp(j); });
1655 }
1656 }
1657
1664
1669 void chmin(const size_t l, const size_t r, const T & v)
1670 {
1672 << "Segment_Tree_Beats::chmin: r=" << r << " >= n=" << n;
1674 << "Segment_Tree_Beats::chmin: l=" << l << " > r=" << r;
1675
1676 chmin_impl(1, 0, n - 1, l, r, v);
1677 }
1678
1683 void chmax(const size_t l, const size_t r, const T & v)
1684 {
1686 << "Segment_Tree_Beats::chmax: r=" << r << " >= n=" << n;
1688 << "Segment_Tree_Beats::chmax: l=" << l << " > r=" << r;
1689
1690 chmax_impl(1, 0, n - 1, l, r, v);
1691 }
1692
1697 T query_sum(const size_t l, const size_t r) const
1698 {
1700 << "Segment_Tree_Beats::query_sum: r=" << r << " >= n=" << n;
1702 << "Segment_Tree_Beats::query_sum: l=" << l << " > r=" << r;
1703
1704 return query_sum_impl(1, 0, n - 1, l, r);
1705 }
1706
1711 T query_max(const size_t l, const size_t r) const
1712 {
1714 << "Segment_Tree_Beats::query_max: r=" << r << " >= n=" << n;
1716 << "Segment_Tree_Beats::query_max: l=" << l << " > r=" << r;
1717
1718 return query_max_impl(1, 0, n - 1, l, r);
1719 }
1720
1725 T query_min(const size_t l, const size_t r) const
1726 {
1728 << "Segment_Tree_Beats::query_min: r=" << r << " >= n=" << n;
1730 << "Segment_Tree_Beats::query_min: l=" << l << " > r=" << r;
1731
1732 return query_min_impl(1, 0, n - 1, l, r);
1733 }
1734
1736 T get(const size_t i) const
1737 {
1738 return query_sum(i, i);
1739 }
1740
1742 [[nodiscard]] constexpr size_t size() const noexcept { return n; }
1743
1745 [[nodiscard]] constexpr bool is_empty() const noexcept { return n == 0; }
1746
1749 {
1750 auto ret = Array<T>::create(n);
1751 for (size_t i = 0; i < n; ++i)
1752 ret(i) = get(i);
1753 return ret;
1754 }
1755
1758 {
1759 tree.swap(other.tree);
1760 std::swap(n, other.n);
1761 }
1762 };
1763
1764} // end namespace Aleph
1765
1766# endif /* TPL_SEGMENT_TREE_H */
Exception handling system with formatted messages for Aleph-w.
#define ah_out_of_range_error_if(C)
Throws std::out_of_range if condition holds.
Definition ah-errors.H:579
Standard functor implementations and comparison objects.
Simple dynamic array with automatic resizing and functional operations.
Definition tpl_array.H:139
static Array create(size_t n)
Create an array with n logical elements.
Definition tpl_array.H:194
void swap(Array &s) noexcept
Swap this with s
Definition tpl_array.H:227
Dynamic singly linked list with functional programming support.
Definition htlist.H:1155
Lazy segment tree with range update and range query.
void build(size_t node, const size_t start, const size_t end)
void point_update(const size_t i, const lazy_type &delta)
Point update: apply delta to a[i].
Gen_Lazy_Segment_Tree(const Array< value_type > &values, Policy p=Policy())
Construct from an Array<value_type>.
void set_impl(size_t node, const size_t start, const size_t end, const size_t idx, const value_type &val)
Gen_Lazy_Segment_Tree(const std::vector< value_type > &values, Policy p=Policy())
Construct from a std::vector.
constexpr size_t size() const noexcept
Number of logical elements.
void update_impl(size_t node, const size_t start, const size_t end, const size_t l, const size_t r, const lazy_type &val)
void fill_and_build(Getter getter)
typename Policy::value_type value_type
value_type query(const size_t l, const size_t r) const
Range query over [l, r].
constexpr bool is_empty() const noexcept
True if the tree contains no elements.
Array< value_type > values() const
Reconstruct all original values into an Array.
Gen_Lazy_Segment_Tree(const DynList< value_type > &values, Policy p=Policy())
Construct from a DynList.
void update(const size_t l, const size_t r, const lazy_type &val)
Range update: apply val to every a[i] with l <= i <= r.
void set(const size_t i, const value_type &val)
Set a[i] = val.
value_type query_impl(size_t node, const size_t start, const size_t end, const size_t l, const size_t r) const
typename Policy::lazy_type lazy_type
void swap(Gen_Lazy_Segment_Tree &other) noexcept(noexcept(std::swap(std::declval< Policy & >(), std::declval< Policy & >())))
Swap this tree with other in O(1).
Gen_Lazy_Segment_Tree(std::initializer_list< value_type > il, Policy p=Policy())
Construct from an initializer list.
Gen_Lazy_Segment_Tree(const size_t num, const value_type &init_val=value_type(), Policy p=Policy())
Construct with num elements, all equal to init_val.
Gen_Lazy_Segment_Tree(const Gen_Lazy_Segment_Tree &)=default
void fill_leaves_recursive(size_t node, size_t start, size_t end, Getter &getter)
void push_down(size_t node, const size_t start, const size_t end) const
value_type get(const size_t i) const
Retrieve the value a[i].
Gen_Lazy_Segment_Tree(Gen_Lazy_Segment_Tree &&) noexcept(std::is_nothrow_move_constructible_v< Array< value_type > > and std::is_nothrow_move_constructible_v< Array< lazy_type > > and std::is_nothrow_move_constructible_v< Policy >)=default
Segment tree over an arbitrary associative binary operation.
void set(const size_t i, const T &val)
Set a[i] = val.
void update_impl(size_t node, const size_t start, const size_t end, const size_t idx, const T &delta)
void swap(Gen_Segment_Tree &other) noexcept(noexcept(std::swap(std::declval< T & >(), std::declval< T & >())) and noexcept(std::swap(std::declval< Op & >(), std::declval< Op & >())))
Swap this tree with other in O(1).
T query(const size_t l, const size_t r) const
Range query over [l, r].
Gen_Segment_Tree(const size_t num, const T &init_val, const T &id, Op oper=Op())
Construct a segment tree with num elements, all equal to init_val.
Gen_Segment_Tree(const Array< T > &values, const T &id, Op oper=Op())
Construct from an Array<T>.
void set_impl(size_t node, const size_t start, const size_t end, const size_t idx, const T &val)
Gen_Segment_Tree(const DynList< T > &values, const T &id, Op oper=Op())
Construct from a DynList<T>.
void fill_from_aleph_it(AlephIt it)
void fill_leaves_recursive(size_t node, size_t start, size_t end, Getter &getter)
T query_impl(size_t node, const size_t start, const size_t end, const size_t l, const size_t r) const
Gen_Segment_Tree(std::initializer_list< T > il, const T &id, Op oper=Op())
Construct from an initializer list.
Gen_Segment_Tree(const Gen_Segment_Tree &)=default
void fill_and_build(Getter getter)
constexpr bool is_empty() const noexcept
True if the tree contains no elements.
Array< T > values() const
Reconstruct all original values into an Array.
T get(const size_t i) const
Retrieve the value a[i].
void update(const size_t i, const T &delta)
Point update: a[i] = Op(a[i], delta).
Gen_Segment_Tree(Gen_Segment_Tree &&) noexcept(std::is_nothrow_move_constructible_v< Array< T > > and std::is_nothrow_move_constructible_v< Op >)=default
constexpr size_t size() const noexcept
Number of logical elements.
void build(size_t node, const size_t start, const size_t end)
Gen_Segment_Tree(const std::vector< T > &values, const T &id, Op oper=Op())
Construct from a std::vector<T>.
Ji Driver's Segment Tree (Segment Tree Beats).
void chmax_impl(size_t node, const size_t start, const size_t end, const size_t l, const size_t r, T v)
void chmax(const size_t l, const size_t r, const T &v)
Range chmax: for each i in [l, r], set a[i] = max(a[i], v).
constexpr size_t size() const noexcept
Number of logical elements.
T query_min_impl(size_t node, const size_t start, const size_t end, const size_t l, const size_t r) const
T query_sum(const size_t l, const size_t r) const
Range sum query over [l, r].
T get(const size_t i) const
Retrieve the value at position i.
void build(size_t node, size_t start, size_t end)
T query_max_impl(size_t node, const size_t start, const size_t end, const size_t l, const size_t r) const
T query_max(const size_t l, const size_t r) const
Range max query over [l, r].
void push_chmin_to_child(size_t child, T v) const
Segment_Tree_Beats(const Array< T > &values)
Construct from an Array<T>.
void fill_and_build(Getter getter)
Segment_Tree_Beats(const size_t num, const T &init_val=T())
Construct with num elements, all equal to init_val.
Segment_Tree_Beats(Segment_Tree_Beats &&) noexcept(std::is_nothrow_move_constructible_v< Array< Node > >)=default
Segment_Tree_Beats(const Segment_Tree_Beats &)=default
Segment_Tree_Beats(const std::vector< T > &values)
Construct from a std::vector<T>.
void push_chmax_to_child(size_t child, T v) const
void chmin(const size_t l, const size_t r, const T &v)
Range chmin: for each i in [l, r], set a[i] = min(a[i], v).
void push_down(size_t node) const
void chmin_impl(size_t node, const size_t start, const size_t end, const size_t l, const size_t r, T v)
Array< T > values() const
Reconstruct all values into an Array.
T query_min(const size_t l, const size_t r) const
Range min query over [l, r].
void swap(Segment_Tree_Beats &other) noexcept
Swap this tree with other in O(1).
constexpr bool is_empty() const noexcept
True if the tree contains no elements.
void pull_up(size_t node) const
void fill_leaves_recursive(const size_t node, size_t start, size_t end, Getter &getter)
T query_sum_impl(size_t node, const size_t start, const size_t end, const size_t l, const size_t r) const
void init_leaf(size_t node, const T &val)
Segment_Tree_Beats(std::initializer_list< T > il)
Construct from an initializer list.
Segment_Tree_Beats(const DynList< T > &values)
Construct from a DynList<T>.
auto get_it() const
Return a properly initialized iterator positioned at the first item on the container.
Definition ah-dry.H:222
iterator begin() noexcept
Return an STL-compatible iterator to the first element.
Binary operation compatible with Segment Tree queries.
Policy concept for lazy segment tree.
pair< size_t, string > P
__gmp_expr< typename __gmp_resolve_expr< T, V >::value_type, __gmp_binary_expr< __gmp_expr< T, U >, __gmp_expr< V, W >, __gmp_max_function > > max(const __gmp_expr< T, U > &expr1, const __gmp_expr< V, W > &expr2)
Definition gmpfrxx.h:4110
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
and
Check uniqueness with explicit hash + equality functors.
Divide_Conquer_DP_Result< Cost > divide_and_conquer_partition_dp(const size_t groups, const size_t n, Transition_Cost_Fn transition_cost, const Cost inf=dp_optimization_detail::default_inf< Cost >())
Optimize partition DP using divide-and-conquer optimization.
std::decay_t< typename HeadC::Item_Type > T
Definition ah-zip.H:105
Itor::difference_type count(const Itor &beg, const Itor &end, const T &value)
Count elements equal to a value.
Definition ahAlgo.H:127
STL namespace.
Range add + range max policy.
static constexpr T compose(const T &old_lazy, const T &new_lazy) noexcept
static constexpr T lazy_identity() noexcept
constexpr T value_identity() const noexcept
static constexpr T combine(const T &a, const T &b) noexcept
static constexpr T apply(const T &val, const T &delta, size_t) noexcept
Range add + range min policy.
static constexpr T lazy_identity() noexcept
static constexpr T compose(const T &old_lazy, const T &new_lazy) noexcept
constexpr T value_identity() const noexcept
static constexpr T apply(const T &val, const T &delta, size_t) noexcept
static constexpr T combine(const T &a, const T &b) noexcept
Range add + range sum policy.
static constexpr T value_identity() noexcept
static constexpr T combine(const T &a, const T &b) noexcept
static constexpr T apply(const T &val, const T &delta, size_t count) noexcept
static constexpr T lazy_identity() noexcept
static constexpr T compose(const T &old_lazy, const T &new_lazy) noexcept
Range assign + range sum policy.
static constexpr T combine(const T &a, const T &b) noexcept
static constexpr T value_identity() noexcept
static constexpr lazy_type lazy_identity() noexcept
std::pair< bool, T > lazy_type
static constexpr T apply(const T &val, const lazy_type &lz, size_t count) noexcept
static constexpr lazy_type compose(const lazy_type &old_lz, const lazy_type &new_lz) noexcept
Lazy segment tree for range add + range max.
Lazy segment tree for range add + range min.
Lazy segment tree for range add + range sum.
Max Segment Tree for range maximum queries with point updates.
Max_Segment_Tree(const size_t num, const T &init_val=std::numeric_limits< T >::lowest())
Construct with num elements, all equal to init_val.
Max_Segment_Tree(const DynList< T > &values)
Construct from a DynList<T>.
Max_Segment_Tree(const std::vector< T > &values)
Construct from a std::vector<T>.
Max_Segment_Tree(std::initializer_list< T > il)
Construct from an initializer list.
Max_Segment_Tree(const Array< T > &values)
Construct from an Array<T>.
Min Segment Tree for range minimum queries with point updates.
Min_Segment_Tree(const size_t num, const T &init_val=std::numeric_limits< T >::max())
Construct with num elements, all equal to init_val.
Min_Segment_Tree(const std::vector< T > &values)
Construct from a std::vector<T>.
Min_Segment_Tree(const DynList< T > &values)
Construct from a DynList<T>.
Min_Segment_Tree(const Array< T > &values)
Construct from an Array<T>.
Min_Segment_Tree(std::initializer_list< T > il)
Construct from an initializer list.
Sum Segment Tree for range sum queries with point updates.
Sum_Segment_Tree(const DynList< T > &values)
Construct from a DynList<T>.
Sum_Segment_Tree(const size_t num, const T &init_val=T())
Construct with num elements, all equal to init_val.
Sum_Segment_Tree(const std::vector< T > &values)
Construct from a std::vector<T>.
Sum_Segment_Tree(const Array< T > &values)
Construct from an Array<T>.
Sum_Segment_Tree(std::initializer_list< T > il)
Construct from an initializer list.
gsl_rng * r
Dynamic array container with automatic resizing.
Alias for htlist.H (DynList implementation).
Sparse Table for static range queries in O(1).
DynList< int > l