Flow
Documentation for the Flow C++ Library
Loading...
Searching...
No Matches
flow_segment_tree.h
Go to the documentation of this file.
1#pragma once
2#include "flow_vector.h"
3#include <cassert>
4#include <optional>
5
6namespace flow {
7
13 template <typename T, typename BinOp, typename Allocator = PolymorphicAllocator<T>>
15 public:
16 using value_type = T;
17 using reference = T&;
18 using const_reference = const T&;
19 using pointer = T*;
20 using const_pointer = const T*;
21 using iterator = T*;
22 using const_iterator = const T*;
23 using difference_type = std::ptrdiff_t;
26
27 private:
29 BinOp binOp_;
30
31 public:
32 constexpr SegmentTree()
33 noexcept(noexcept(container_type()) && noexcept(BinOp()))
34 : data_(), binOp_() {
35 }
36
37 explicit constexpr SegmentTree(const allocator_type& allocator)
38 noexcept(noexcept(container_type(allocator)) && noexcept(BinOp()))
39 : data_(allocator), binOp_(){
40 }
41
42 constexpr SegmentTree(const SegmentTree&) = default;
43 constexpr SegmentTree(const SegmentTree& rhs, const allocator_type& allocator)
44 : data_(rhs.data_, allocator), binOp_(rhs.binOp_) {
45 }
46
47 constexpr SegmentTree(SegmentTree&&) = default;
48 constexpr SegmentTree(SegmentTree&& rhs, const allocator_type& allocator)
49 noexcept(noexcept(container_type(std::move(rhs.data_), allocator)) && noexcept(BinOp(std::move(rhs.binOp_))))
50 : data_(std::move(rhs.data_), allocator), binOp_(std::move(rhs.binOp_)) {
51 }
52
58 template <std::forward_iterator It>
59 explicit constexpr SegmentTree(It first, It last, BinOp binOp = {}, const allocator_type& allocator = {})
60 : data_(std::distance(first, last) * 2, allocator), binOp_(std::move(binOp)) {
61 std::copy(first, last, data_.begin() + size());
63 }
64
69 explicit constexpr SegmentTree(std::initializer_list<T> list, BinOp binOp = {}, const allocator_type& allocator = {})
70 : SegmentTree(list.begin(), list.end(), std::move(binOp), allocator) {
71 }
72
73 ~SegmentTree() = default;
74
75 // Allocator.
76 allocator_type get_allocator() const noexcept {
77 return data_.get_allocator();
78 }
79
80 // Accessor.
81
84 constexpr std::size_t size() const {
85 return data_.size() / 2;
86 }
87
90 constexpr bool empty() const {
91 return data_.empty();
92 }
93
97 constexpr void setPoint(std::size_t i, const T& value) {
98 i += size();
99 data_[i] = value;
100 while (hasParent(i)) {
101 std::size_t parent = getParent(i);
102 std::size_t sibling = getSibling(i);
103 data_[parent] = binOp_(data_[i], data_[sibling]);
104 i = parent;
105 }
106 }
107
113 constexpr std::optional<T> getRange(std::size_t first, std::size_t last) const {
114 assert(first <= last && "invalid range");
115 std::size_t elementSize = size();
116 first += elementSize;
117 last += elementSize;
118
119 std::optional<T> result{};
120 for (; first < last;) {
121 if (isRightChild(first)) {
122 if (!result) {
123 result = data_[first];
124 } else {
125 *result = binOp_(*result, data_[first]);
126 }
127 ++first;
128 }
129
130 if (isRightChild(last)) {
131 --last;
132 if (!result) {
133 result = data_[last];
134 } else {
135 *result = binOp_(*result, data_[last]);
136 }
137 }
138
139 first = getParent(first);
140 last = getParent(last);
141 }
142
143 return result;
144 }
145
146 private:
147 constexpr void buildParent() {
148 for (std::size_t i = size(); i-- > 1;) {
149 std::size_t left = getLeftChild(i);
150 std::size_t right = left + 1;
151 data_[i] = binOp_(data_[left], data_[right]);
152 }
153 }
154
155 static constexpr bool hasParent(std::size_t i) noexcept {
156 return i > 1;
157 }
158
159 static constexpr std::size_t getParent(std::size_t i) noexcept {
160 assert(hasParent(i) && "calling parent on the root node");
161 return i / 2;
162 }
163
164 static constexpr std::size_t getLeftChild(std::size_t i) noexcept {
165 return i * 2;
166 }
167
168 static constexpr std::size_t getSibling(std::size_t i) noexcept {
169 return i ^ 1;
170 }
171
172 static constexpr bool isLeftChild(std::size_t i) noexcept {
173 return (i % 2) == 0;
174 }
175
176 static constexpr bool isRightChild(std::size_t i) noexcept {
177 return !isLeftChild(i);
178 }
179 };
180}
constexpr SegmentTree(std::initializer_list< T > list, BinOp binOp={}, const allocator_type &allocator={})
Initializer list constructor.
static constexpr std::size_t getSibling(std::size_t i) noexcept
constexpr SegmentTree(const SegmentTree &rhs, const allocator_type &allocator)
constexpr bool empty() const
Check if the segmeent tree is empty.
std::ptrdiff_t difference_type
constexpr void setPoint(std::size_t i, const T &value)
Set the new value at index i, then update the tree structure.
constexpr SegmentTree(SegmentTree &&rhs, const allocator_type &allocator) noexcept(noexcept(container_type(std::move(rhs.data_), allocator)) &&noexcept(BinOp(std::move(rhs.binOp_))))
constexpr SegmentTree(SegmentTree &&)=default
container_type data_
Vector< T, Allocator > container_type
constexpr std::size_t size() const
Return the number of input elements. This only counts the leaf node from the input.
constexpr std::optional< T > getRange(std::size_t first, std::size_t last) const
Query the value from [first, last) after applying the binary operator adjacent-pair wise....
static constexpr bool isRightChild(std::size_t i) noexcept
constexpr SegmentTree(const allocator_type &allocator) noexcept(noexcept(container_type(allocator)) &&noexcept(BinOp()))
static constexpr std::size_t getParent(std::size_t i) noexcept
static constexpr bool isLeftChild(std::size_t i) noexcept
allocator_type get_allocator() const noexcept
constexpr SegmentTree(It first, It last, BinOp binOp={}, const allocator_type &allocator={})
Iterator range constructor.
constexpr SegmentTree() noexcept(noexcept(container_type()) &&noexcept(BinOp()))
~SegmentTree()=default
container_type::allocator_type allocator_type
constexpr SegmentTree(const SegmentTree &)=default
static constexpr std::size_t getLeftChild(std::size_t i) noexcept
constexpr void buildParent()
static constexpr bool hasParent(std::size_t i) noexcept
iterator begin() noexcept