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 <tpl_array.H>
78# include <tpl_dynList.H>
79# include <ahFunction.H>
80# include <ah-errors.H>
81
82namespace Aleph
83{
88 template <typename T>
90 std::is_arithmetic_v<T> &&
91 std::totally_ordered<T> &&
92 std::is_signed_v<T> &&
93 !std::same_as<T, bool>;
94
102 template <typename F, typename T>
104 requires(const F& f, const T& a, const T& b)
105 {
106 { f(a, b) } -> std::convertible_to<T>;
107 };
108
139 template <typename T,
140 class Plus = Aleph::plus<T>,
141 class Minus = Aleph::minus<T>>
144 {
145 protected:
146 Array<T> tree; // 1-indexed internal storage (position 0 unused)
147 size_t n = 0; // number of logical elements (0-indexed: 0..n-1)
148
151
157 static constexpr size_t lowbit(size_t x) noexcept
158 {
159 return x & (~x + 1);
160 }
161
164 void build()
165 {
166 for (size_t i = 1; i <= n; ++i)
167 if (const size_t parent = i + lowbit(i); parent <= n)
168 tree(parent) = plus_op(tree(parent), tree(i));
169 }
170
172 template <class F>
174 {
175 for (size_t i = 0; i < n; ++i)
176 tree(i + 1) = getter(i);
177 build();
178 }
179
181 template <class StdIt>
183 {
184 size_t i = 1;
185 for (; first != last; ++first)
186 tree(i++) = *first;
187 build();
188 }
189
191 template <class AlephIt>
193 {
194 size_t i = 1;
195 for (; it.has_curr(); it.next_ne())
196 tree(i++) = it.get_curr();
197 build();
198 }
199
200 public:
202 using Item_Type = T;
203
211 Gen_Fenwick_Tree(const size_t num,
212 Plus pop = Plus(), Minus mop = Minus())
213 : tree(num + 1, T()), n(num),
214 plus_op(pop), minus_op(mop)
215 {
216 // empty — all elements are identity
217 }
218
227 Gen_Fenwick_Tree(std::initializer_list<T> il,
228 Plus pop = Plus(), Minus mop = Minus())
229 : tree(il.size() + 1, T()), n(il.size()),
230 plus_op(pop), minus_op(mop)
231 {
232 fill_from_std_iter(il.begin(), il.end());
233 }
234
242 Plus pop = Plus(), Minus mop = Minus())
243 : tree(values.size() + 1, T()), n(values.size()),
244 plus_op(pop), minus_op(mop)
245 {
246 fill_from_indexed([&values](size_t i) { return values(i); });
247 }
248
258 Gen_Fenwick_Tree(const std::vector<T> & values,
259 Plus pop = Plus(), Minus mop = Minus())
260 : tree(values.size() + 1, T()), n(values.size()),
261 plus_op(pop), minus_op(mop)
262 {
263 fill_from_indexed([&values](size_t i) { return values[i]; });
264 }
265
273 Plus pop = Plus(), Minus mop = Minus())
274 : tree(values.size() + 1, T()), n(values.size()),
275 plus_op(pop), minus_op(mop)
276 {
277 fill_from_aleph_it(values.get_it());
278 }
279
281
283
285
287
294 void update(size_t i, const T & delta)
295 {
297 << "Gen_Fenwick_Tree::update: index " << i << " >= size " << n;
298
299 for (++i; i <= n; i += i & (-i))
300 tree(i) = plus_op(tree(i), delta);
301 }
302
309 T prefix(size_t i) const
310 {
312 << "Gen_Fenwick_Tree::prefix: index " << i << " >= size " << n;
313
314 T s = T();
315 for (++i; i > 0; i -= i & (-i))
316 s = plus_op(s, tree(i));
317 return s;
318 }
319
327 T query(const size_t l, const size_t r) const
328 {
330 << "Gen_Fenwick_Tree::query: r=" << r << " >= n=" << n;
332 << "Gen_Fenwick_Tree::query: l=" << l << " > r=" << r;
333
334 return l > 0 ? minus_op(prefix(r), prefix(l - 1)) : prefix(r);
335 }
336
344 T get(const size_t i) const
345 {
346 return query(i, i);
347 }
348
357 void set(const size_t i, const T & value)
358 {
359 update(i, minus_op(value, get(i)));
360 }
361
363 [[nodiscard]] constexpr size_t size() const noexcept { return n; }
364
366 [[nodiscard]] constexpr bool is_empty() const noexcept { return n == 0; }
367
373 {
374 auto ret = Array<T>::create(n);
375 for (size_t i = 0; i < n; ++i)
376 ret(i) = get(i);
377 return ret;
378 }
379
381 void swap(Gen_Fenwick_Tree & other) noexcept
382 {
383 tree.swap(other.tree);
384 std::swap(n, other.n);
385 std::swap(plus_op, other.plus_op);
386 std::swap(minus_op, other.minus_op);
387 }
388 };
389
390
410 template <FenwickArithmetic T>
412 : public Gen_Fenwick_Tree<T, Aleph::plus<T>, Aleph::minus<T>>
413 {
415 using Base::Base; // inherit all constructors
416
432 size_t find_kth(T k) const requires std::integral<T>
433 {
434 const size_t nn = this->n;
435 if (nn == 0)
436 return 0;
437
438 size_t pos = 0;
439 // highest power of 2 that is <= nn
440 size_t bit_mask = std::bit_floor(nn);
441
442 while (bit_mask > 0)
443 {
444 if (const size_t next = pos + bit_mask; next <= nn && this->tree(next) < k)
445 {
446 k -= this->tree(next);
447 pos = next;
448 }
449 bit_mask >>= 1;
450 }
451
452 return pos < nn ? pos : nn;
453 }
454 };
455
496 template <FenwickArithmetic T>
498 {
499 Gen_Fenwick_Tree<T> b1; // stores differences d[i]
500 Gen_Fenwick_Tree<T> b2; // stores d[i] * i
501 size_t n = 0;
502
504 T prefix_sum(size_t i) const
505 {
506 return static_cast<T>(i + 1) * b1.prefix(i) - b2.prefix(i);
507 }
508
511 {
512 auto d2 = Array<T>::create(n);
513 d2(0) = T();
514 for (size_t i = 1; i < n; ++i)
515 d2(i) = d(i) * static_cast<T>(i);
516
519 b1.swap(new_b1);
520 b2.swap(new_b2);
521 }
522
523 public:
524 using Item_Type = T;
525
527 Range_Fenwick_Tree(const size_t num)
528 : b1(num), b2(num), n(num)
529 {
530 // empty — all elements are identity
531 }
532
541 Range_Fenwick_Tree(std::initializer_list<T> il)
542 : b1(il.size()), b2(il.size()), n(il.size())
543 {
544 if (n == 0)
545 return;
546
547 auto d = Array<T>::create(n);
548 auto it = il.begin();
549 d(0) = *it;
550 T prev = *it++;
551 for (size_t i = 1; i < n; ++i, ++it)
552 {
553 d(i) = *it - prev;
554 prev = *it;
555 }
557 }
558
564 : b1(values.size()), b2(values.size()), n(values.size())
565 {
566 if (n == 0)
567 return;
568
569 auto d = Array<T>::create(n);
570 d(0) = values(0);
571 for (size_t i = 1; i < n; ++i)
572 d(i) = values(i) - values(i - 1);
574 }
575
577
579
581
583
592 void update(size_t l, const size_t r, const T & delta)
593 {
595 << "Range_Fenwick_Tree::update: l=" << l << " > r=" << r;
597 << "Range_Fenwick_Tree::update: r=" << r << " >= size " << n;
598
599 b1.update(l, delta);
600 b2.update(l, delta * static_cast<T>(l));
601
602 if (r + 1 < n)
603 {
604 T neg = -delta;
605 b1.update(r + 1, neg);
606 b2.update(r + 1, neg * static_cast<T>(r + 1));
607 }
608 }
609
614 void point_update(const size_t i, const T & delta)
615 {
616 update(i, i, delta);
617 }
618
625 T prefix(const size_t i) const
626 {
628 << "Range_Fenwick_Tree::prefix: index " << i << " >= size " << n;
629
630 return prefix_sum(i);
631 }
632
640 T query(const size_t l, const size_t r) const
641 {
643 << "Range_Fenwick_Tree::query: r=" << r << " >= n=" << n;
645 << "Range_Fenwick_Tree::query: l=" << l << " > r=" << r;
646
647 return l > 0 ? prefix_sum(r) - prefix_sum(l - 1) : prefix_sum(r);
648 }
649
654 T get(const size_t i) const
655 {
656 return query(i, i);
657 }
658
663 void set(const size_t i, const T & value)
664 {
665 point_update(i, value - get(i));
666 }
667
669 [[nodiscard]] constexpr size_t size() const noexcept { return n; }
670
672 [[nodiscard]] constexpr bool is_empty() const noexcept { return n == 0; }
673
679 {
680 auto ret = Array<T>::create(n);
681 for (size_t i = 0; i < n; ++i)
682 ret(i) = get(i);
683 return ret;
684 }
685
688 {
689 b1.swap(other.b1);
690 b2.swap(other.b2);
691 std::swap(n, other.n);
692 }
693 };
694} // end namespace Aleph
695
696# endif /* TPL_FENWICK_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:138
static Array create(size_t n)
Create an array with n logical elements.
Definition tpl_array.H:191
void swap(Array &s) noexcept
Swap this with s
Definition tpl_array.H:221
Dynamic singly linked list with functional programming support.
Definition htlist.H:1423
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:190
iterator end() noexcept
Return an STL-compatible end iterator.
iterator begin() noexcept
Return an STL-compatible iterator to the first element.
Arithmetic domain accepted by Fenwick specializations.
Binary operation compatible with Fenwick tree group functors.
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:107
static void prefix(Node *root, DynList< Node * > &acc)
void next()
Advance all underlying iterators (bounds-checked).
Definition ah-zip.H:175
DynList< T > maps(const C &c, Op op)
Classic map operation.
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.
Dynamic array container with automatic resizing.
Alias for htlist.H (DynList implementation).
DynList< int > l