Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
tpl_fenwick_tree.H
Go to the documentation of this file.
1/*
2 Aleph_w
3
4 Data structures & Algorithms
5 version 2.0.0b
6 https://github.com/lrleon/Aleph-w
7
8 This file is part of Aleph-w library
9
10 Copyright (c) 2002-2026 Leandro Rabindranath Leon
11
12 Permission is hereby granted, free of charge, to any person obtaining a copy
13 of this software and associated documentation files (the "Software"), to deal
14 in the Software without restriction, including without limitation the rights
15 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16 copies of the Software, and to permit persons to whom the Software is
17 furnished to do so, subject to the following conditions:
18
19 The above copyright notice and this permission notice shall be included in all
20 copies or substantial portions of the Software.
21
22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28 SOFTWARE.
29*/
30
31
67# ifndef TPL_FENWICK_TREE_H
68# define TPL_FENWICK_TREE_H
69
70# include <bit>
71# include <cassert>
72# include <concepts>
73# include <initializer_list>
74# include <type_traits>
75# include <vector>
76# include <utility>
77# include <ah-concepts.H>
78# include <tpl_array.H>
79# include <tpl_dynList.H>
80# include <ahFunction.H>
81# include <ah-errors.H>
82
83namespace Aleph
84{
89 template <typename T>
91 std::is_arithmetic_v<T> &&
92 std::totally_ordered<T> &&
93 std::is_signed_v<T> &&
94 !std::same_as<T, bool>;
95
102 template <typename F, typename T>
104
135 template <typename T,
136 class Plus = Aleph::plus<T>,
137 class Minus = Aleph::minus<T>>
140 {
141 protected:
142 Array<T> tree; // 1-indexed internal storage (position 0 unused)
143 size_t n = 0; // number of logical elements (0-indexed: 0..n-1)
144
147
153 static constexpr size_t lowbit(size_t x) noexcept
154 {
155 return x & (~x + 1);
156 }
157
160 void build()
161 {
162 for (size_t i = 1; i <= n; ++i)
163 if (const size_t parent = i + lowbit(i); parent <= n)
164 tree(parent) = plus_op(tree(parent), tree(i));
165 }
166
168 template <class F>
170 {
171 for (size_t i = 0; i < n; ++i)
172 tree(i + 1) = getter(i);
173 build();
174 }
175
177 template <class StdIt>
179 {
180 size_t i = 1;
181 for (; first != last; ++first)
182 tree(i++) = *first;
183 build();
184 }
185
187 template <class AlephIt>
189 {
190 size_t i = 1;
191 for (; it.has_curr(); it.next_ne())
192 tree(i++) = it.get_curr();
193 build();
194 }
195
196 public:
198 using Item_Type = T;
199
207 Gen_Fenwick_Tree(const size_t num,
208 Plus pop = Plus(), Minus mop = Minus())
209 : tree(num + 1, T()), n(num),
210 plus_op(pop), minus_op(mop)
211 {
212 // empty — all elements are identity
213 }
214
223 Gen_Fenwick_Tree(std::initializer_list<T> il,
224 Plus pop = Plus(), Minus mop = Minus())
225 : tree(il.size() + 1, T()), n(il.size()),
226 plus_op(pop), minus_op(mop)
227 {
228 fill_from_std_iter(il.begin(), il.end());
229 }
230
238 Plus pop = Plus(), Minus mop = Minus())
239 : tree(values.size() + 1, T()), n(values.size()),
240 plus_op(pop), minus_op(mop)
241 {
242 fill_from_indexed([&values](size_t i) { return values(i); });
243 }
244
254 Gen_Fenwick_Tree(const std::vector<T> & values,
255 Plus pop = Plus(), Minus mop = Minus())
256 : tree(values.size() + 1, T()), n(values.size()),
257 plus_op(pop), minus_op(mop)
258 {
259 fill_from_indexed([&values](size_t i) { return values[i]; });
260 }
261
269 Plus pop = Plus(), Minus mop = Minus())
270 : tree(values.size() + 1, T()), n(values.size()),
271 plus_op(pop), minus_op(mop)
272 {
273 fill_from_aleph_it(values.get_it());
274 }
275
277
279
281
283
290 void update(size_t i, const T & delta)
291 {
293 << "Gen_Fenwick_Tree::update: index " << i << " >= size " << n;
294
295 for (++i; i <= n; i += i & (-i))
296 tree(i) = plus_op(tree(i), delta);
297 }
298
305 T prefix(size_t i) const
306 {
308 << "Gen_Fenwick_Tree::prefix: index " << i << " >= size " << n;
309
310 T s = T();
311 for (++i; i > 0; i -= i & (-i))
312 s = plus_op(s, tree(i));
313 return s;
314 }
315
323 T query(const size_t l, const size_t r) const
324 {
326 << "Gen_Fenwick_Tree::query: r=" << r << " >= n=" << n;
328 << "Gen_Fenwick_Tree::query: l=" << l << " > r=" << r;
329
330 return l > 0 ? minus_op(prefix(r), prefix(l - 1)) : prefix(r);
331 }
332
340 T get(const size_t i) const
341 {
342 return query(i, i);
343 }
344
353 void set(const size_t i, const T & value)
354 {
355 update(i, minus_op(value, get(i)));
356 }
357
359 [[nodiscard]] constexpr size_t size() const noexcept { return n; }
360
362 [[nodiscard]] constexpr bool is_empty() const noexcept { return n == 0; }
363
369 {
370 auto ret = Array<T>::create(n);
371 for (size_t i = 0; i < n; ++i)
372 ret(i) = get(i);
373 return ret;
374 }
375
377 void swap(Gen_Fenwick_Tree & other) noexcept
378 {
379 tree.swap(other.tree);
380 std::swap(n, other.n);
381 std::swap(plus_op, other.plus_op);
382 std::swap(minus_op, other.minus_op);
383 }
384 };
385
386
406 template <FenwickArithmetic T>
408 : public Gen_Fenwick_Tree<T, Aleph::plus<T>, Aleph::minus<T>>
409 {
411 using Base::Base; // inherit all constructors
412
428 size_t find_kth(T k) const requires std::integral<T>
429 {
430 const size_t nn = this->n;
431 if (nn == 0)
432 return 0;
433
434 size_t pos = 0;
435 // highest power of 2 that is <= nn
436 size_t bit_mask = std::bit_floor(nn);
437
438 while (bit_mask > 0)
439 {
440 if (const size_t next = pos + bit_mask; next <= nn && this->tree(next) < k)
441 {
442 k -= this->tree(next);
443 pos = next;
444 }
445 bit_mask >>= 1;
446 }
447
448 return pos < nn ? pos : nn;
449 }
450 };
451
492 template <FenwickArithmetic T>
494 {
495 Gen_Fenwick_Tree<T> b1; // stores differences d[i]
496 Gen_Fenwick_Tree<T> b2; // stores d[i] * i
497 size_t n = 0;
498
500 T prefix_sum(size_t i) const
501 {
502 return static_cast<T>(i + 1) * b1.prefix(i) - b2.prefix(i);
503 }
504
507 {
508 auto d2 = Array<T>::create(n);
509 d2(0) = T();
510 for (size_t i = 1; i < n; ++i)
511 d2(i) = d(i) * static_cast<T>(i);
512
515 b1.swap(new_b1);
516 b2.swap(new_b2);
517 }
518
519 public:
520 using Item_Type = T;
521
523 Range_Fenwick_Tree(const size_t num)
524 : b1(num), b2(num), n(num)
525 {
526 // empty — all elements are identity
527 }
528
537 Range_Fenwick_Tree(std::initializer_list<T> il)
538 : b1(il.size()), b2(il.size()), n(il.size())
539 {
540 if (n == 0)
541 return;
542
543 auto d = Array<T>::create(n);
544 auto it = il.begin();
545 d(0) = *it;
546 T prev = *it++;
547 for (size_t i = 1; i < n; ++i, ++it)
548 {
549 d(i) = *it - prev;
550 prev = *it;
551 }
553 }
554
560 : b1(values.size()), b2(values.size()), n(values.size())
561 {
562 if (n == 0)
563 return;
564
565 auto d = Array<T>::create(n);
566 d(0) = values(0);
567 for (size_t i = 1; i < n; ++i)
568 d(i) = values(i) - values(i - 1);
570 }
571
573
575
577
579
588 void update(size_t l, const size_t r, const T & delta)
589 {
591 << "Range_Fenwick_Tree::update: l=" << l << " > r=" << r;
593 << "Range_Fenwick_Tree::update: r=" << r << " >= size " << n;
594
595 b1.update(l, delta);
596 b2.update(l, delta * static_cast<T>(l));
597
598 if (r + 1 < n)
599 {
600 T neg = -delta;
601 b1.update(r + 1, neg);
602 b2.update(r + 1, neg * static_cast<T>(r + 1));
603 }
604 }
605
610 void point_update(const size_t i, const T & delta)
611 {
612 update(i, i, delta);
613 }
614
621 T prefix(const size_t i) const
622 {
624 << "Range_Fenwick_Tree::prefix: index " << i << " >= size " << n;
625
626 return prefix_sum(i);
627 }
628
636 T query(const size_t l, const size_t r) const
637 {
639 << "Range_Fenwick_Tree::query: r=" << r << " >= n=" << n;
641 << "Range_Fenwick_Tree::query: l=" << l << " > r=" << r;
642
643 return l > 0 ? prefix_sum(r) - prefix_sum(l - 1) : prefix_sum(r);
644 }
645
650 T get(const size_t i) const
651 {
652 return query(i, i);
653 }
654
659 void set(const size_t i, const T & value)
660 {
661 point_update(i, value - get(i));
662 }
663
665 [[nodiscard]] constexpr size_t size() const noexcept { return n; }
666
668 [[nodiscard]] constexpr bool is_empty() const noexcept { return n == 0; }
669
675 {
676 auto ret = Array<T>::create(n);
677 for (size_t i = 0; i < n; ++i)
678 ret(i) = get(i);
679 return ret;
680 }
681
684 {
685 b1.swap(other.b1);
686 b2.swap(other.b2);
687 std::swap(n, other.n);
688 }
689 };
690} // end namespace Aleph
691
692# endif /* TPL_FENWICK_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.
size_t size_t int32_t value
Definition ca-c-api.h:116
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
Fenwick tree over an arbitrary abelian group.
void fill_from_std_iter(StdIt first, StdIt last)
Fill the internal storage from a standard iterator range and build.
Array< T > values() const
Reconstruct all original values into an Array.
T query(const size_t l, const size_t r) const
Range query: Plus(a[l], a[l+1], ..., a[r]).
constexpr bool is_empty() const noexcept
True if the tree contains no elements.
Gen_Fenwick_Tree(const DynList< T > &values, Plus pop=Plus(), Minus mop=Minus())
Construct from a DynList<T> in O(n) time.
void set(const size_t i, const T &value)
Set a[i] = value.
void fill_from_aleph_it(AlephIt it)
Fill the internal storage from an Aleph-style iterator (get_it()) and build.
void swap(Gen_Fenwick_Tree &other) noexcept
Swap this tree with other in O(1).
T prefix(size_t i) const
Prefix query: Plus(a[0], a[1], ..., a[i]).
T get(const size_t i) const
Retrieve the logical value a[i].
void build()
O(n) bottom-up construction of the tree array from raw values already placed in tree[1....
Gen_Fenwick_Tree(const Gen_Fenwick_Tree &)=default
Gen_Fenwick_Tree(const size_t num, Plus pop=Plus(), Minus mop=Minus())
Construct a tree with num elements, all equal to the identity T().
static constexpr size_t lowbit(size_t x) noexcept
Return the least significant set bit of x (as a mask).
void fill_from_indexed(F getter)
Fill the internal storage from a 0-based indexed getter and build.
T Item_Type
The type of element stored in the tree.
Gen_Fenwick_Tree(Gen_Fenwick_Tree &&) noexcept=default
Gen_Fenwick_Tree(const Array< T > &values, Plus pop=Plus(), Minus mop=Minus())
Construct from an Array<T> in O(n) time.
Gen_Fenwick_Tree(std::initializer_list< T > il, Plus pop=Plus(), Minus mop=Minus())
Construct from an initializer list in O(n) time.
Gen_Fenwick_Tree(const std::vector< T > &values, Plus pop=Plus(), Minus mop=Minus())
Construct from a std::vector<T> in O(n) time.
constexpr size_t size() const noexcept
Number of logical elements.
Fenwick tree supporting range updates and range queries.
Gen_Fenwick_Tree< T > b2
void build_from_diffs(const Array< T > &d)
Rebuild b1 and b2 from a difference array stored in d.
void point_update(const size_t i, const T &delta)
Point update: add delta to a[i].
Range_Fenwick_Tree(const size_t num)
Construct a tree with num elements, all zero.
void update(size_t l, const size_t r, const T &delta)
Range update: add delta to every a[i] with l <= i <= r.
constexpr bool is_empty() const noexcept
True if the tree contains no elements.
Range_Fenwick_Tree(Range_Fenwick_Tree &&) noexcept=default
void swap(Range_Fenwick_Tree &other) noexcept
Swap this tree with other in O(1).
T get(const size_t i) const
Retrieve the logical value a[i].
void set(const size_t i, const T &value)
Set a[i] = value.
Range_Fenwick_Tree(const Array< T > &values)
Construct from an Array<T> in O(n) time.
Range_Fenwick_Tree(std::initializer_list< T > il)
Construct from an initializer list in O(n) time.
Range_Fenwick_Tree(const Range_Fenwick_Tree &)=default
Array< T > values() const
Reconstruct all original values into an Array.
T prefix(const size_t i) const
Prefix query: sum of a[0..i].
Gen_Fenwick_Tree< T > b1
constexpr size_t size() const noexcept
Number of logical elements.
T query(const size_t l, const size_t r) const
Range query: sum of a[l..r].
T prefix_sum(size_t i) const
Internal: prefix sum P(i) = (i+1)*B1.prefix(i) - B2.prefix(i)
auto get_it() const
Return a properly initialized iterator positioned at the first item on the container.
Definition ah-dry.H:228
A binary functor closed over T.
Arithmetic domain accepted by Fenwick specializations.
Binary operation compatible with Fenwick tree group functors.
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
size_t size(Node *root) noexcept
std::decay_t< typename HeadC::Item_Type > T
Definition ah-zip.H:105
static void prefix(Node *root, DynList< Node * > &acc)
void next()
Advance all underlying iterators (bounds-checked).
Definition ah-zip.H:171
Fenwick tree for arithmetic types with find_kth support.
size_t find_kth(T k) const
Find the smallest 0-based index i such that prefix(i) >= k.
static int * k
gsl_rng * r
Dynamic array container with automatic resizing.
Alias for htlist.H (DynList implementation).
DynList< int > l