feat: add generic iterative segment tree class
This commit is contained in:
@@ -0,0 +1,69 @@
|
||||
#pragma once
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
|
||||
#define LEFT(i) (i << 1)
|
||||
#define RIGHT(i) ((i << 1) | 1)
|
||||
#define IS_RIGHT_CHILD(i) ((i) & 1)
|
||||
|
||||
template <typename T>
|
||||
class IterSegTree {
|
||||
private:
|
||||
int len_;
|
||||
std::vector<T> seg_tree_;
|
||||
std::function<T(T, T)> combine_;
|
||||
T iota_;
|
||||
|
||||
void build(const std::vector<T>& base_array) {
|
||||
// n to 2n-1 => total n elements => leaves
|
||||
for (int i = len_; i < 2 * len_; i++) {
|
||||
seg_tree_[i] = base_array[i - len_];
|
||||
}
|
||||
// reverse as back to front is going up the tree
|
||||
for (int i = len_ - 1; i > 0; i--) {
|
||||
seg_tree_[i] = combine_(seg_tree_[LEFT(i)], seg_tree_[RIGHT(i)]);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
IterSegTree(const std::vector<T>& base_array,
|
||||
std::function<T(T, T)> combine_func, T iota_value)
|
||||
: combine_(combine_func), iota_(iota_value) {
|
||||
len_ = base_array.size();
|
||||
seg_tree_.resize(2 * len_ + 1);
|
||||
build(base_array);
|
||||
}
|
||||
|
||||
IterSegTree(int len, T iota)
|
||||
: len_(len), iota_(iota), seg_tree_(2 * len_ + 1, iota_) {}
|
||||
|
||||
void update(int index, std::function<T(T)> transform) {
|
||||
// 1. go to leaf and update
|
||||
index += len_;
|
||||
seg_tree_[index] = transform(seg_tree_[index]);
|
||||
|
||||
while (index > 1) { // we don't use 0
|
||||
index >>= 1; // move to parent first
|
||||
seg_tree_[index] =
|
||||
combine_(seg_tree_[LEFT(index)], seg_tree_[RIGHT(index)]);
|
||||
}
|
||||
}
|
||||
|
||||
// for range [l,r)
|
||||
T query(int left, int right) {
|
||||
left += len_;
|
||||
right += len_;
|
||||
|
||||
T result = iota_;
|
||||
// NOTE: this soln assumes combine_ is commutative,
|
||||
// else you need to separarte left and right accumulators
|
||||
for (; left < right; left >>= 1, right >>= 1) {
|
||||
if (IS_RIGHT_CHILD(left))
|
||||
result = combine_(result, seg_tree_[left++]);
|
||||
if (IS_RIGHT_CHILD(right))
|
||||
result = combine_(result, seg_tree_[--right]);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,45 @@
|
||||
#pragma once
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
|
||||
#define LEFT(i) (i << 1)
|
||||
#define RIGHT(i) ((i << 1) | 1)
|
||||
#define IS_RIGHT_CHILD(i) ((i) & 1)
|
||||
|
||||
// REMEMBER REMEMBER REMEMBER REMEMBER
|
||||
// Invariant: tree[p] will reflect the effect ot lazy[p]
|
||||
// the lazy is not for the node, but for the children
|
||||
|
||||
template <typename T, typename L>
|
||||
class IterLazySegTree {
|
||||
private:
|
||||
int n_, h_;
|
||||
std::vector<T> tree_;
|
||||
std::vector<L> lazy_;
|
||||
|
||||
T iota_;
|
||||
L iota_lazy_;
|
||||
|
||||
std::function<T(T, T)> combine_;
|
||||
std::function<L(L, L)> combine_lazy_;
|
||||
std::function<T(T, L, int)> apply_lazy_;
|
||||
|
||||
void apply(int index, L new_lazy, int len) {
|
||||
// invariant: tree_[index] has no lazy, so just need the
|
||||
// new val to be applied
|
||||
tree_[index] = apply_lazy_(tree_[index], new_lazy, len);
|
||||
|
||||
if (index < n_) { // not leaf
|
||||
// combine lazy for children
|
||||
lazy_[index] = combine_lazy_(lazy_[index], new_lazy);
|
||||
}
|
||||
}
|
||||
|
||||
void push(int index) {
|
||||
for (int cur_h = h_; cur_h > 0; cur_h--) {
|
||||
int par_at_level_cur_h = index >> cur_h;
|
||||
if (lazy_[par_at_level_cur_h] != iota_lazy_) {
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user