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 <ah-concepts.H>
74# include <tpl_array.H>
75# include <tpl_dynList.H>
76# include <ahFunction.H>
77# include <ah-errors.H>
78# include <tpl_sparse_table.H>
79
80namespace Aleph
81{
98 template <typename F, typename T>
100
101 // ================================================================
102 // Gen_Segment_Tree — Point update + Range query
103 // ================================================================
104
141 template <typename T, class Op>
142 requires SegmentTreeOp<Op, T>
144 {
145 Array<T> tree; // 1-indexed implicit binary tree
146 size_t n = 0; // number of logical elements
147 T identity; // identity element of the monoid
148 Op op;
149
150 void build(size_t node, const size_t start, const size_t end)
151 {
152 if (start == end)
153 return;
154
155 const size_t mid = start + (end - start) / 2;
156 build(2 * node, start, mid);
157 build(2 * node + 1, mid + 1, end);
158 tree(node) = op(tree(2 * node), tree(2 * node + 1));
159 }
160
161 void update_impl(size_t node, const size_t start, const size_t end,
162 const size_t idx, const T & delta)
163 {
164 if (start == end)
165 {
166 tree(node) = op(tree(node), delta);
167 return;
168 }
169
170 if (const size_t mid = start + (end - start) / 2; idx <= mid)
171 update_impl(2 * node, start, mid, idx, delta);
172 else
173 update_impl(2 * node + 1, mid + 1, end, idx, delta);
174
175 tree(node) = op(tree(2 * node), tree(2 * node + 1));
176 }
177
178 void set_impl(size_t node, const size_t start, const size_t end,
179 const size_t idx, const T & val)
180 {
181 if (start == end)
182 {
183 tree(node) = val;
184 return;
185 }
186
187 if (const size_t mid = start + (end - start) / 2; idx <= mid)
188 set_impl(2 * node, start, mid, idx, val);
189 else
190 set_impl(2 * node + 1, mid + 1, end, idx, val);
191
192 tree(node) = op(tree(2 * node), tree(2 * node + 1));
193 }
194
195 T query_impl(size_t node, const size_t start, const size_t end,
196 const size_t l, const size_t r) const
197 {
198 if (r < start || end < l)
199 return identity;
200
201 if (l <= start and end <= r)
202 return tree(node);
203
204 const size_t mid = start + (end - start) / 2;
205 return op(query_impl(2 * node, start, mid, l, r),
206 query_impl(2 * node + 1, mid + 1, end, l, r));
207 }
208
209 template <class Getter>
211 {
212 // Place values in leaves via recursive descent
213 fill_leaves_recursive(1, 0, n - 1, getter);
214
215 // Build internal nodes bottom-up
216 build(1, 0, n - 1);
217 }
218
219 template <class Getter>
220 void fill_leaves_recursive(size_t node, size_t start, size_t end,
221 Getter & getter)
222 {
223 if (start == end)
224 {
225 tree(node) = getter(start);
226 return;
227 }
228
229 const size_t mid = start + (end - start) / 2;
230 fill_leaves_recursive(2 * node, start, mid, getter);
231 fill_leaves_recursive(2 * node + 1, mid + 1, end, getter);
232 }
233
234 template <class AlephIt>
236 {
237 auto tmp = Array<T>::create(n);
238 size_t i = 0;
239 for (; it.has_curr(); it.next_ne())
240 tmp(i++) = it.get_curr();
241
242 auto getter = [&tmp](size_t j) { return tmp(j); };
244 }
245
246 public:
247 using Item_Type = T;
248
257 Gen_Segment_Tree(const size_t num, const T & init_val,
258 const T & id, Op oper = Op())
259 : tree(num == 0 ? 1 : 4 * num, id),
260 n(num), identity(id), op(oper)
261 {
262 if (n > 0)
263 fill_and_build([&init_val](size_t) { return init_val; });
264 }
265
278 Gen_Segment_Tree(std::initializer_list<T> il,
279 const T & id, Op oper = Op())
280 : tree(il.size() == 0 ? 1 : 4 * il.size(), id),
281 n(il.size()), identity(id), op(oper)
282 {
283 if (n > 0)
284 {
285 auto it = il.begin();
286 fill_and_build([&it](size_t) { return *it++; });
287 }
288 }
289
297 const T & id, Op oper = Op())
298 : tree(values.size() == 0 ? 1 : 4 * values.size(), id),
299 n(values.size()), identity(id), op(oper)
300 {
301 if (n > 0)
302 fill_and_build([&values](size_t i) { return values(i); });
303 }
304
311 Gen_Segment_Tree(const std::vector<T> & values,
312 const T & id, Op oper = Op())
313 : tree(values.size() == 0 ? 1 : 4 * values.size(), id),
314 n(values.size()), identity(id), op(oper)
315 {
316 if (n > 0)
317 fill_and_build([&values](size_t i) { return values[i]; });
318 }
319
327 const T & id, Op oper = Op())
328 : tree(values.size() == 0 ? 1 : 4 * values.size(), id),
329 n(values.size()), identity(id), op(oper)
330 {
331 if (n > 0)
332 fill_from_aleph_it(values.get_it());
333 }
334
336
340
342
346
353 void update(const size_t i, const T & delta)
354 {
356 << "Gen_Segment_Tree::update: index " << i << " >= size " << n;
357
358 update_impl(1, 0, n - 1, i, delta);
359 }
360
367 void set(const size_t i, const T & val)
368 {
370 << "Gen_Segment_Tree::set: index " << i << " >= size " << n;
371
372 set_impl(1, 0, n - 1, i, val);
373 }
374
384 T query(const size_t l, const size_t r) const
385 {
387 << "Gen_Segment_Tree::query: r=" << r << " >= n=" << n;
389 << "Gen_Segment_Tree::query: l=" << l << " > r=" << r;
390
391 return query_impl(1, 0, n - 1, l, r);
392 }
393
401 T get(const size_t i) const
402 {
404 << "Gen_Segment_Tree::get: index " << i << " >= size " << n;
405
406 return query_impl(1, 0, n - 1, i, i);
407 }
408
410 [[nodiscard]] constexpr size_t size() const noexcept { return n; }
411
413 [[nodiscard]] constexpr bool is_empty() const noexcept { return n == 0; }
414
420 {
421 auto ret = Array<T>::create(n);
422 for (size_t i = 0; i < n; ++i)
423 ret(i) = get(i);
424 return ret;
425 }
426
428 void swap(Gen_Segment_Tree & other) noexcept(
429 noexcept(std::swap(std::declval<T&>(), std::declval<T&>())) and
430 noexcept(std::swap(std::declval<Op&>(), std::declval<Op&>())))
431 {
432 tree.swap(other.tree);
433 std::swap(n, other.n);
434 std::swap(identity, other.identity);
435 std::swap(op, other.op);
436 }
437 };
438
439
457 template <typename T>
459 : public Gen_Segment_Tree<T, Aleph::plus<T>>
460 {
462
469 Sum_Segment_Tree(const size_t num, const T & init_val = T())
470 : Base(num, init_val, T())
471 {}
472
478 Sum_Segment_Tree(std::initializer_list<T> il)
479 : Base(il, T())
480 {}
481
488 : Base(values, T())
489 {}
490
496 Sum_Segment_Tree(const std::vector<T> & values)
497 : Base(values, T())
498 {}
499
506 : Base(values, T())
507 {}
508 };
509
530 template <std::totally_ordered T>
532 : public Gen_Segment_Tree<T, Min_Op<T>>
533 {
535
542 Min_Segment_Tree(const size_t num,
543 const T & init_val = std::numeric_limits<T>::max())
544 : Base(num, init_val, std::numeric_limits<T>::max())
545 {}
546
552 Min_Segment_Tree(std::initializer_list<T> il)
553 : Base(il, std::numeric_limits<T>::max())
554 {}
555
564
570 Min_Segment_Tree(const std::vector<T> & values)
572 {}
573
582 };
583
605 template <std::totally_ordered T>
607 : public Gen_Segment_Tree<T, Max_Op<T>>
608 {
610
617 Max_Segment_Tree(const size_t num,
618 const T & init_val = std::numeric_limits<T>::lowest())
619 : Base(num, init_val, std::numeric_limits<T>::lowest())
620 {}
621
627 Max_Segment_Tree(std::initializer_list<T> il)
628 : Base(il, std::numeric_limits<T>::lowest())
629 {}
630
637 : Base(values, std::numeric_limits<T>::lowest())
638 {}
639
645 Max_Segment_Tree(const std::vector<T> & values)
646 : Base(values, std::numeric_limits<T>::lowest())
647 {}
648
655 : Base(values, std::numeric_limits<T>::lowest())
656 {}
657 };
658
659
660 // ================================================================
661 // Gen_Lazy_Segment_Tree — Range update + Range query
662 // ================================================================
663
689 template <typename P>
691 std::equality_comparable<typename P::lazy_type> and
692 requires(const P& p,
693 const typename P::value_type& v1,
694 const typename P::value_type& v2,
695 const typename P::lazy_type& lz1,
696 const typename P::lazy_type& lz2,
697 size_t count)
698 {
699 typename P::value_type;
700 typename P::lazy_type;
701 { p.combine(v1, v2) } -> std::convertible_to<typename P::value_type>;
702 { p.apply(v1, lz1, count) } -> std::convertible_to<typename P::value_type>;
703 { p.compose(lz1, lz2) } -> std::convertible_to<typename P::lazy_type>;
704 { p.value_identity() } -> std::convertible_to<typename P::value_type>;
705 { p.lazy_identity() } -> std::convertible_to<typename P::lazy_type>;
706 };
707
721 template <typename T>
723 {
724 using value_type = T;
725 using lazy_type = T;
726
727 static constexpr T combine(const T & a, const T & b) noexcept
728 {
729 return a + b;
730 }
731
732 static constexpr T apply(const T & val, const T & delta,
733 size_t count) noexcept
734 {
735 return val + delta * static_cast<T>(count);
736 }
737
738 static constexpr T compose(const T & old_lazy,
739 const T & new_lazy) noexcept
740 {
741 return old_lazy + new_lazy;
742 }
743
744 static constexpr T value_identity() noexcept { return T(); }
745 static constexpr T lazy_identity() noexcept { return T(); }
746 };
747
761 template <std::totally_ordered T>
763 {
764 using value_type = T;
765 using lazy_type = T;
766
767 static constexpr T combine(const T & a, const T & b) noexcept
768 {
769 return a <= b ? a : b;
770 }
771
772 static constexpr T apply(const T & val, const T & delta,
773 size_t) noexcept
774 {
775 return val + delta;
776 }
777
778 static constexpr T compose(const T & old_lazy,
779 const T & new_lazy) noexcept
780 {
781 return old_lazy + new_lazy;
782 }
783
785 {
786 return std::numeric_limits<T>::max();
787 }
788
789 static constexpr T lazy_identity() noexcept { return T(); }
790 };
791
805 template <std::totally_ordered T>
807 {
808 using value_type = T;
809 using lazy_type = T;
810
811 static constexpr T combine(const T & a, const T & b) noexcept
812 {
813 return a >= b ? a : b;
814 }
815
816 static constexpr T apply(const T & val, const T & delta,
817 size_t) noexcept
818 {
819 return val + delta;
820 }
821
822 static constexpr T compose(const T & old_lazy,
823 const T & new_lazy) noexcept
824 {
825 return old_lazy + new_lazy;
826 }
827
829 {
830 return std::numeric_limits<T>::lowest();
831 }
832
833 static constexpr T lazy_identity() noexcept { return T(); }
834 };
835
855 template <typename T>
857 {
858 using value_type = T;
859 using lazy_type = std::pair<bool, T>;
860
861 static constexpr T combine(const T & a, const T & b) noexcept
862 {
863 return a + b;
864 }
865
866 static constexpr T apply(const T & val, const lazy_type & lz,
867 size_t count) noexcept
868 {
869 return lz.first ? lz.second * static_cast<T>(count) : val;
870 }
871
872 static constexpr lazy_type compose(const lazy_type & old_lz,
873 const lazy_type & new_lz) noexcept
874 {
875 return new_lz.first ? new_lz : old_lz;
876 }
877
878 static constexpr T value_identity() noexcept { return T(); }
879
881 {
882 return {false, T()};
883 }
884 };
885
886
915 template <typename Policy>
918 {
919 public:
920 using value_type = typename Policy::value_type;
921 using lazy_type = typename Policy::lazy_type;
923
924 private:
927 size_t n = 0;
929
930 void push_down(size_t node, const size_t start, const size_t end) const
931 {
932 if (lazy(node) == pol.lazy_identity())
933 return;
934
935 const size_t mid = start + (end - start) / 2;
936 const size_t left = 2 * node;
937 const size_t right = 2 * node + 1;
938
939 tree(left) = pol.apply(tree(left), lazy(node), mid - start + 1);
940 lazy(left) = pol.compose(lazy(left), lazy(node));
941
942 tree(right) = pol.apply(tree(right), lazy(node), end - mid);
943 lazy(right) = pol.compose(lazy(right), lazy(node));
944
945 lazy(node) = pol.lazy_identity();
946 }
947
948 void build(size_t node, const size_t start, const size_t end)
949 {
950 if (start == end)
951 return;
952
953 const size_t mid = start + (end - start) / 2;
954 build(2 * node, start, mid);
955 build(2 * node + 1, mid + 1, end);
956 tree(node) = pol.combine(tree(2 * node), tree(2 * node + 1));
957 }
958
959 void update_impl(size_t node, const size_t start, const size_t end,
960 const size_t l, const size_t r, const lazy_type & val)
961 {
962 if (r < start or end < l)
963 return;
964
965 if (l <= start and end <= r)
966 {
967 tree(node) = pol.apply(tree(node), val, end - start + 1);
968 lazy(node) = pol.compose(lazy(node), val);
969 return;
970 }
971
972 push_down(node, start, end);
973
974 const size_t mid = start + (end - start) / 2;
975 update_impl(2 * node, start, mid, l, r, val);
976 update_impl(2 * node + 1, mid + 1, end, l, r, val);
977 tree(node) = pol.combine(tree(2 * node), tree(2 * node + 1));
978 }
979
980 value_type query_impl(size_t node, const size_t start, const size_t end,
981 const size_t l, const size_t r) const
982 {
983 if (r < start or end < l)
984 return pol.value_identity();
985
986 if (l <= start and end <= r)
987 return tree(node);
988
989 push_down(node, start, end);
990
991 const size_t mid = start + (end - start) / 2;
992 return pol.combine(
993 query_impl(2 * node, start, mid, l, r),
994 query_impl(2 * node + 1, mid + 1, end, l, r));
995 }
996
997 void set_impl(size_t node, const size_t start, const size_t end,
998 const size_t idx, const value_type & val)
999 {
1000 if (start == end)
1001 {
1002 tree(node) = val;
1003 lazy(node) = pol.lazy_identity();
1004 return;
1005 }
1006
1007 push_down(node, start, end);
1008
1009 if (const size_t mid = start + (end - start) / 2; idx <= mid)
1010 set_impl(2 * node, start, mid, idx, val);
1011 else
1012 set_impl(2 * node + 1, mid + 1, end, idx, val);
1013
1014 tree(node) = pol.combine(tree(2 * node), tree(2 * node + 1));
1015 }
1016
1017 template <class Getter>
1019 {
1020 fill_leaves_recursive(1, 0, n - 1, getter);
1021 build(1, 0, n - 1);
1022 }
1023
1024 template <class Getter>
1025 void fill_leaves_recursive(size_t node, size_t start, size_t end,
1026 Getter & getter)
1027 {
1028 if (start == end)
1029 {
1030 tree(node) = getter(start);
1031 return;
1032 }
1033
1034 const size_t mid = start + (end - start) / 2;
1035 fill_leaves_recursive(2 * node, start, mid, getter);
1036 fill_leaves_recursive(2 * node + 1, mid + 1, end, getter);
1037 }
1038
1039 template <class AlephIt>
1041 {
1043 size_t i = 0;
1044 for (; it.has_curr(); it.next_ne())
1045 tmp(i++) = it.get_curr();
1046
1047 auto getter = [&tmp](size_t j) { return tmp(j); };
1049 }
1050
1051 size_t alloc_size() const
1052 {
1053 return n == 0 ? 1 : 4 * n;
1054 }
1055
1056 public:
1058 Gen_Lazy_Segment_Tree(const size_t num,
1059 const value_type & init_val = value_type(),
1060 Policy p = Policy())
1061 : tree(num == 0 ? 1 : 4 * num, p.value_identity()),
1062 lazy(num == 0 ? 1 : 4 * num, p.lazy_identity()),
1063 n(num), pol(p)
1064 {
1065 if (n > 0)
1066 fill_and_build([&init_val](size_t) { return init_val; });
1067 }
1068
1070 Gen_Lazy_Segment_Tree(std::initializer_list<value_type> il,
1071 Policy p = Policy())
1072 : tree(il.size() == 0 ? 1 : 4 * il.size(), p.value_identity()),
1073 lazy(il.size() == 0 ? 1 : 4 * il.size(), p.lazy_identity()),
1074 n(il.size()), pol(p)
1075 {
1076 if (n > 0)
1077 {
1078 auto it = il.begin();
1079 fill_and_build([&it](size_t) { return *it++; });
1080 }
1081 }
1082
1085 Policy p = Policy())
1086 : tree(values.size() == 0 ? 1 : 4 * values.size(), p.value_identity()),
1087 lazy(values.size() == 0 ? 1 : 4 * values.size(), p.lazy_identity()),
1088 n(values.size()), pol(p)
1089 {
1090 if (n > 0)
1091 fill_and_build([&values](size_t i) { return values(i); });
1092 }
1093
1095 Gen_Lazy_Segment_Tree(const std::vector<value_type> & values,
1096 Policy p = Policy())
1097 : tree(values.size() == 0 ? 1 : 4 * values.size(), p.value_identity()),
1098 lazy(values.size() == 0 ? 1 : 4 * values.size(), p.lazy_identity()),
1099 n(values.size()), pol(p)
1100 {
1101 if (n > 0)
1102 fill_and_build([&values](size_t i) { return values[i]; });
1103 }
1104
1107 Policy p = Policy())
1108 : tree(values.size() == 0 ? 1 : 4 * values.size(), p.value_identity()),
1109 lazy(values.size() == 0 ? 1 : 4 * values.size(), p.lazy_identity()),
1110 n(values.size()), pol(p)
1111 {
1112 if (n > 0)
1114 }
1115
1117
1122
1124
1129
1138 void update(const size_t l, const size_t r, const lazy_type & val)
1139 {
1141 << "Gen_Lazy_Segment_Tree::update: r=" << r << " >= n=" << n;
1143 << "Gen_Lazy_Segment_Tree::update: l=" << l << " > r=" << r;
1144
1145 update_impl(1, 0, n - 1, l, r, val);
1146 }
1147
1152 void point_update(const size_t i, const lazy_type & delta)
1153 {
1154 update(i, i, delta);
1155 }
1156
1165 void set(const size_t i, const value_type & val)
1166 {
1168 << "Gen_Lazy_Segment_Tree::set: index " << i << " >= size " << n;
1169
1170 set_impl(1, 0, n - 1, i, val);
1171 }
1172
1184 value_type query(const size_t l, const size_t r) const
1185 {
1187 << "Gen_Lazy_Segment_Tree::query: r=" << r << " >= n=" << n;
1189 << "Gen_Lazy_Segment_Tree::query: l=" << l << " > r=" << r;
1190
1191 return query_impl(1, 0, n - 1, l, r);
1192 }
1193
1198 value_type get(const size_t i) const
1199 {
1200 return query(i, i);
1201 }
1202
1204 [[nodiscard]] constexpr size_t size() const noexcept { return n; }
1205
1207 [[nodiscard]] constexpr bool is_empty() const noexcept { return n == 0; }
1208
1214 {
1216 for (size_t i = 0; i < n; ++i)
1217 ret(i) = get(i);
1218 return ret;
1219 }
1220
1223 noexcept(std::swap(std::declval<Policy&>(), std::declval<Policy&>())))
1224 {
1225 tree.swap(other.tree);
1226 lazy.swap(other.lazy);
1227 std::swap(n, other.n);
1228 std::swap(pol, other.pol);
1229 }
1230 };
1231
1232
1237 template <typename T>
1239 : public Gen_Lazy_Segment_Tree<Add_Sum_Policy<T>>
1240 {
1242 using Base::Base;
1243 };
1244
1253 template <std::totally_ordered T>
1255 : public Gen_Lazy_Segment_Tree<Add_Min_Policy<T>>
1256 {
1258 using Base::Base;
1259 };
1260
1269 template <std::totally_ordered T>
1271 : public Gen_Lazy_Segment_Tree<Add_Max_Policy<T>>
1272 {
1274 using Base::Base;
1275 };
1276
1277
1278 // ================================================================
1279 // Segment_Tree_Beats — Ji Driver's Segment Tree
1280 // ================================================================
1281
1309 template <typename T>
1310 requires std::is_arithmetic_v<T> and std::is_signed_v<T>
1312 {
1319
1321 size_t n = 0;
1322
1323 static constexpr T INF = std::numeric_limits<T>::max();
1324 static constexpr T NEG_INF = std::numeric_limits<T>::lowest();
1325
1326 void init_leaf(size_t node, const T & val)
1327 {
1328 tree(node) = {val, NEG_INF, val, INF, val,
1329 1, 1, INF, NEG_INF};
1330 }
1331
1332 void pull_up(size_t node) const
1333 {
1334 const auto & l = tree(2 * node);
1335 const auto & r = tree(2 * node + 1);
1336
1337 tree(node).sum = l.sum + r.sum;
1338
1339 // max
1340 if (l.max_val > r.max_val)
1341 {
1342 tree(node).max_val = l.max_val;
1343 tree(node).count_max = l.count_max;
1344 tree(node).second_max = std::max(l.second_max, r.max_val);
1345 }
1346 else if (l.max_val < r.max_val)
1347 {
1348 tree(node).max_val = r.max_val;
1349 tree(node).count_max = r.count_max;
1350 tree(node).second_max = std::max(l.max_val, r.second_max);
1351 }
1352 else
1353 {
1354 tree(node).max_val = l.max_val;
1355 tree(node).count_max = l.count_max + r.count_max;
1356 tree(node).second_max = std::max(l.second_max, r.second_max);
1357 }
1358
1359 // min
1360 if (l.min_val < r.min_val)
1361 {
1362 tree(node).min_val = l.min_val;
1363 tree(node).count_min = l.count_min;
1364 tree(node).second_min = std::min(l.second_min, r.min_val);
1365 }
1366 else if (l.min_val > r.min_val)
1367 {
1368 tree(node).min_val = r.min_val;
1369 tree(node).count_min = r.count_min;
1370 tree(node).second_min = std::min(l.min_val, r.second_min);
1371 }
1372 else
1373 {
1374 tree(node).min_val = l.min_val;
1375 tree(node).count_min = l.count_min + r.count_min;
1376 tree(node).second_min = std::min(l.second_min, r.second_min);
1377 }
1378
1379 tree(node).lazy_chmin = INF;
1380 tree(node).lazy_chmax = NEG_INF;
1381 }
1382
1383 void push_chmin_to_child(size_t child, T v) const
1384 {
1385 auto & nd = tree(child);
1386 if (v >= nd.max_val)
1387 return;
1388
1389 nd.sum -= static_cast<T>(nd.count_max) * (nd.max_val - v);
1390
1391 // If all elements in this node are the same value (max == min),
1392 // then reducing max also reduces min
1393 if (nd.min_val == nd.max_val)
1394 nd.min_val = v;
1395 if (nd.second_min == nd.max_val)
1396 nd.second_min = v;
1397
1398 nd.max_val = v;
1399
1400 // Compose with existing lazy tags
1401 nd.lazy_chmin = std::min(nd.lazy_chmin, v);
1402 nd.lazy_chmax = std::min(nd.lazy_chmax, v);
1403 }
1404
1405 void push_chmax_to_child(size_t child, T v) const
1406 {
1407 auto & nd = tree(child);
1408 if (v <= nd.min_val)
1409 return;
1410
1411 nd.sum += static_cast<T>(nd.count_min) * (v - nd.min_val);
1412
1413 // If all elements are the same value, raising min also raises max
1414 if (nd.max_val == nd.min_val)
1415 nd.max_val = v;
1416 if (nd.second_max == nd.min_val)
1417 nd.second_max = v;
1418
1419 nd.min_val = v;
1420
1421 // Compose with existing lazy tags
1422 nd.lazy_chmax = std::max(nd.lazy_chmax, v);
1423 nd.lazy_chmin = std::max(nd.lazy_chmin, v);
1424 }
1425
1426 void push_down(size_t node) const
1427 {
1428 auto & nd = tree(node);
1429
1430 // Push chmax first (raise minimum), then chmin (lower maximum)
1431 // This order is critical for correctness
1432 if (nd.lazy_chmax != NEG_INF)
1433 {
1434 push_chmax_to_child(2 * node, nd.lazy_chmax);
1435 push_chmax_to_child(2 * node + 1, nd.lazy_chmax);
1436 nd.lazy_chmax = NEG_INF;
1437 }
1438
1439 if (nd.lazy_chmin != INF)
1440 {
1441 push_chmin_to_child(2 * node, nd.lazy_chmin);
1442 push_chmin_to_child(2 * node + 1, nd.lazy_chmin);
1443 nd.lazy_chmin = INF;
1444 }
1445 }
1446
1447 void build(size_t node, size_t start, size_t end)
1448 {
1449 if (start == end)
1450 return;
1451
1452 const size_t mid = start + (end - start) / 2;
1453 build(2 * node, start, mid);
1454 build(2 * node + 1, mid + 1, end);
1455 pull_up(node);
1456 }
1457
1458 void chmin_impl(size_t node, const size_t start, const size_t end,
1459 const size_t l, const size_t r, T v)
1460 {
1461 if (r < start or end < l or tree(node).max_val <= v)
1462 return;
1463
1464 if (l <= start and end <= r and tree(node).second_max < v)
1465 {
1466 push_chmin_to_child(node, v);
1467 return;
1468 }
1469
1470 push_down(node);
1471 const size_t mid = start + (end - start) / 2;
1472 chmin_impl(2 * node, start, mid, l, r, v);
1473 chmin_impl(2 * node + 1, mid + 1, end, l, r, v);
1474 pull_up(node);
1475 }
1476
1477 void chmax_impl(size_t node, const size_t start, const size_t end,
1478 const size_t l, const size_t r, T v)
1479 {
1480 if (r < start or end < l or tree(node).min_val >= v)
1481 return;
1482
1483 if (l <= start and end <= r and tree(node).second_min > v)
1484 {
1485 push_chmax_to_child(node, v);
1486 return;
1487 }
1488
1489 push_down(node);
1490 const size_t mid = start + (end - start) / 2;
1491 chmax_impl(2 * node, start, mid, l, r, v);
1492 chmax_impl(2 * node + 1, mid + 1, end, l, r, v);
1493 pull_up(node);
1494 }
1495
1496 T query_sum_impl(size_t node, const size_t start, const size_t end,
1497 const size_t l, const size_t r) const
1498 {
1499 if (r < start or end < l)
1500 return T();
1501
1502 if (l <= start and end <= r)
1503 return tree(node).sum;
1504
1505 push_down(node);
1506 const size_t mid = start + (end - start) / 2;
1507 return query_sum_impl(2 * node, start, mid, l, r) +
1508 query_sum_impl(2 * node + 1, mid + 1, end, l, r);
1509 }
1510
1511 T query_max_impl(size_t node, const size_t start, const size_t end,
1512 const size_t l, const size_t r) const
1513 {
1514 if (r < start or end < l)
1515 return NEG_INF;
1516
1517 if (l <= start and end <= r)
1518 return tree(node).max_val;
1519
1520 push_down(node);
1521 const size_t mid = start + (end - start) / 2;
1522 return std::max(query_max_impl(2 * node, start, mid, l, r),
1523 query_max_impl(2 * node + 1, mid + 1, end, l, r));
1524 }
1525
1526 T query_min_impl(size_t node, const size_t start, const size_t end,
1527 const size_t l, const size_t r) const
1528 {
1529 if (r < start or end < l)
1530 return INF;
1531
1532 if (l <= start and end <= r)
1533 return tree(node).min_val;
1534
1535 push_down(node);
1536 const size_t mid = start + (end - start) / 2;
1537 return std::min(query_min_impl(2 * node, start, mid, l, r),
1538 query_min_impl(2 * node + 1, mid + 1, end, l, r));
1539 }
1540
1541 template <class Getter>
1543 {
1544 fill_leaves_recursive(1, 0, n - 1, getter);
1545 build(1, 0, n - 1);
1546 }
1547
1548 template <class Getter>
1549 void fill_leaves_recursive(const size_t node, size_t start, size_t end,
1550 Getter & getter)
1551 {
1552 if (start == end)
1553 {
1554 init_leaf(node, getter(start));
1555 return;
1556 }
1557
1558 const size_t mid = start + (end - start) / 2;
1559 fill_leaves_recursive(2 * node, start, mid, getter);
1560 fill_leaves_recursive(2 * node + 1, mid + 1, end, getter);
1561 }
1562
1564 {
1565 Node def = {NEG_INF, NEG_INF, INF, INF, T(),
1566 0, 0, INF, NEG_INF};
1567 for (size_t i = 0; i < tree.size(); ++i)
1568 tree(i) = def;
1569 }
1570
1571 public:
1572 using Item_Type = T;
1573
1580 Segment_Tree_Beats(const size_t num, const T & init_val = T())
1581 : tree(Array<Node>::create(num == 0 ? 1 : 4 * num)), n(num)
1582 {
1584 if (n > 0)
1585 fill_and_build([&init_val](size_t) { return init_val; });
1586 }
1587
1593 Segment_Tree_Beats(std::initializer_list<T> il)
1594 : tree(Array<Node>::create(il.size() == 0 ? 1 : 4 * il.size())),
1595 n(il.size())
1596 {
1598 if (n > 0)
1599 {
1600 auto it = il.begin();
1601 fill_and_build([&it](size_t) { return *it++; });
1602 }
1603 }
1604
1611 : tree(Array<Node>::create(values.size() == 0 ? 1 : 4 * values.size())),
1612 n(values.size())
1613 {
1615 if (n > 0)
1616 fill_and_build([&values](size_t i) { return values(i); });
1617 }
1618
1624 Segment_Tree_Beats(const std::vector<T> & values)
1625 : tree(Array<Node>::create(values.size() == 0 ? 1 : 4 * values.size())),
1626 n(values.size())
1627 {
1629 if (n > 0)
1630 fill_and_build([&values](size_t i) { return values[i]; });
1631 }
1632
1639 : tree(Array<Node>::create(values.size() == 0 ? 1 : 4 * values.size())),
1640 n(values.size())
1641 {
1643 if (n > 0)
1644 {
1645 auto tmp = Array<T>::create(n);
1646 size_t i = 0;
1647 for (auto it = values.get_it(); it.has_curr(); it.next_ne())
1648 tmp(i++) = it.get_curr();
1649 fill_and_build([&tmp](size_t j) { return tmp(j); });
1650 }
1651 }
1652
1659
1664 void chmin(const size_t l, const size_t r, const T & v)
1665 {
1667 << "Segment_Tree_Beats::chmin: r=" << r << " >= n=" << n;
1669 << "Segment_Tree_Beats::chmin: l=" << l << " > r=" << r;
1670
1671 chmin_impl(1, 0, n - 1, l, r, v);
1672 }
1673
1678 void chmax(const size_t l, const size_t r, const T & v)
1679 {
1681 << "Segment_Tree_Beats::chmax: r=" << r << " >= n=" << n;
1683 << "Segment_Tree_Beats::chmax: l=" << l << " > r=" << r;
1684
1685 chmax_impl(1, 0, n - 1, l, r, v);
1686 }
1687
1692 T query_sum(const size_t l, const size_t r) const
1693 {
1695 << "Segment_Tree_Beats::query_sum: r=" << r << " >= n=" << n;
1697 << "Segment_Tree_Beats::query_sum: l=" << l << " > r=" << r;
1698
1699 return query_sum_impl(1, 0, n - 1, l, r);
1700 }
1701
1706 T query_max(const size_t l, const size_t r) const
1707 {
1709 << "Segment_Tree_Beats::query_max: r=" << r << " >= n=" << n;
1711 << "Segment_Tree_Beats::query_max: l=" << l << " > r=" << r;
1712
1713 return query_max_impl(1, 0, n - 1, l, r);
1714 }
1715
1720 T query_min(const size_t l, const size_t r) const
1721 {
1723 << "Segment_Tree_Beats::query_min: r=" << r << " >= n=" << n;
1725 << "Segment_Tree_Beats::query_min: l=" << l << " > r=" << r;
1726
1727 return query_min_impl(1, 0, n - 1, l, r);
1728 }
1729
1731 T get(const size_t i) const
1732 {
1733 return query_sum(i, i);
1734 }
1735
1737 [[nodiscard]] constexpr size_t size() const noexcept { return n; }
1738
1740 [[nodiscard]] constexpr bool is_empty() const noexcept { return n == 0; }
1741
1744 {
1745 auto ret = Array<T>::create(n);
1746 for (size_t i = 0; i < n; ++i)
1747 ret(i) = get(i);
1748 return ret;
1749 }
1750
1753 {
1754 tree.swap(other.tree);
1755 std::swap(n, other.n);
1756 }
1757 };
1758
1759} // end namespace Aleph
1760
1761# endif /* TPL_SEGMENT_TREE_H */
C++20 concepts hub: comparison, BST policy, and Aleph container concepts.
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:584
Standard functor implementations and comparison objects.
Simple dynamic array with automatic resizing and functional operations.
Definition tpl_array.H:138
static Array create(size_t n)
Create an array with n logical elements.
Definition tpl_array.H:196
void swap(Array &s) noexcept
Swap this with s
Definition tpl_array.H:232
Doubly-linked list (defined in tpl_dynList.H).
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:228
iterator begin() noexcept
Return an STL-compatible iterator to the first element.
A binary functor closed over T.
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:4121
size_t blossom_maximum_cardinality_matching(const GT &g, DynDlist< typename GT::Arc * > &matching, SA sa=SA())
Alias of compute_maximum_cardinality_general_matching().
Definition Blossom.H:466
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
and
Check uniqueness with explicit hash + equality functors.
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