From a5921bdcf96e76c85323243071cea495554ee41e Mon Sep 17 00:00:00 2001 From: ruinivist Date: Mon, 9 Feb 2026 23:26:16 +0000 Subject: [PATCH] feat: add generic iterative segment tree class --- .gitignore | 3 +- iter-seg-tree/CMakeLists.txt | 8 + iter-seg-tree/include/iter_seg_tree.hpp | 69 +++ iter-seg-tree/include/iter_seg_tree_lazy.hpp | 45 ++ iter-seg-tree/sim.html | 445 +++++++++++++++++++ iter-seg-tree/src/main.cpp | 14 + 6 files changed, 583 insertions(+), 1 deletion(-) create mode 100644 iter-seg-tree/CMakeLists.txt create mode 100644 iter-seg-tree/include/iter_seg_tree.hpp create mode 100644 iter-seg-tree/include/iter_seg_tree_lazy.hpp create mode 100644 iter-seg-tree/sim.html create mode 100644 iter-seg-tree/src/main.cpp diff --git a/.gitignore b/.gitignore index 684b757..7d3a08a 100644 --- a/.gitignore +++ b/.gitignore @@ -56,4 +56,5 @@ Thumbs.db .cache # binary -sub_notifs \ No newline at end of file +sub_notifs +iter_seg_tree \ No newline at end of file diff --git a/iter-seg-tree/CMakeLists.txt b/iter-seg-tree/CMakeLists.txt new file mode 100644 index 0000000..029013a --- /dev/null +++ b/iter-seg-tree/CMakeLists.txt @@ -0,0 +1,8 @@ +cmake_minimum_required(VERSION 4.0) + +project(iter_seg_tree) +set(CMAKE_CXX_STANDARD 20) + +add_executable(iter_seg_tree src/main.cpp) + +target_include_directories(iter_seg_tree PRIVATE ${CMAKE_SOURCE_DIR}/include) \ No newline at end of file diff --git a/iter-seg-tree/include/iter_seg_tree.hpp b/iter-seg-tree/include/iter_seg_tree.hpp new file mode 100644 index 0000000..639abf5 --- /dev/null +++ b/iter-seg-tree/include/iter_seg_tree.hpp @@ -0,0 +1,69 @@ +#pragma once +#include +#include + +#define LEFT(i) (i << 1) +#define RIGHT(i) ((i << 1) | 1) +#define IS_RIGHT_CHILD(i) ((i) & 1) + +template +class IterSegTree { + private: + int len_; + std::vector seg_tree_; + std::function combine_; + T iota_; + + void build(const std::vector& 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& base_array, + std::function 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 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; + } +}; \ No newline at end of file diff --git a/iter-seg-tree/include/iter_seg_tree_lazy.hpp b/iter-seg-tree/include/iter_seg_tree_lazy.hpp new file mode 100644 index 0000000..0a787cb --- /dev/null +++ b/iter-seg-tree/include/iter_seg_tree_lazy.hpp @@ -0,0 +1,45 @@ +#pragma once +#include +#include + +#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 +class IterLazySegTree { + private: + int n_, h_; + std::vector tree_; + std::vector lazy_; + + T iota_; + L iota_lazy_; + + std::function combine_; + std::function combine_lazy_; + std::function 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_) { + } + } + } +}; \ No newline at end of file diff --git a/iter-seg-tree/sim.html b/iter-seg-tree/sim.html new file mode 100644 index 0000000..35a3349 --- /dev/null +++ b/iter-seg-tree/sim.html @@ -0,0 +1,445 @@ + + + + + + Iterative SegTree (Dark Mode) + + + +

Iterative Segment Tree

+ +
+ + + to + + + + +
+ +
+
+ Ready. Set the range and click "Start Query". +
+
+ Accumulator: +
+
+ +
+ + + + diff --git a/iter-seg-tree/src/main.cpp b/iter-seg-tree/src/main.cpp new file mode 100644 index 0000000..9356ca6 --- /dev/null +++ b/iter-seg-tree/src/main.cpp @@ -0,0 +1,14 @@ +#include +#include + +// this isn't ideal +#include "../include/iter_seg_tree.hpp" + +int main() { + auto sum = [](int a, int b) { return a + b; }; + + std::vector vec = {1, 2, 3, 4}; + IterSegTree st(vec, sum, 0); + + std::cout << st.query(0, 2) << "\n"; +} \ No newline at end of file