Class: DataStructuresRMolinari::SegmentTreeTemplate
- Inherits:
-
Object
- Object
- DataStructuresRMolinari::SegmentTreeTemplate
- Includes:
- Shared::BinaryTreeArithmetic
- Defined in:
- lib/data_structures_rmolinari/segment_tree_template.rb
Overview
The template of Segment Tree, which can be used for various interval-related purposes, like efficiently finding the sum (or min or max) on a arbitrary subarray of a given array.
There is an excellent description of the data structure at cp-algorithms.com/data_structures/segment_tree.html. The Wikipedia article (en.wikipedia.org/wiki/Segment_tree) appears to describe a different data structure which is sometimes called an “interval tree.”
For more details (and some close-to-metal analysis of run time, especially for large datasets) see en.algorithmica.org/hpc/data-structures/segment-trees/. In particular, this shows how to do a bottom-up implementation, which is faster, at least for large datasets and cache-relevant compiled code. These issues don’t really apply to code written in Ruby.
This is a generic implementation, intended to allow easy configuration for concrete instances. See the parameters to the initializer and the definitions of concrete realisations like MaxValSegmentTree.
We do O(n) work to build the internal data structure at initialization. Then we answer queries in O(log n) time.
Instance Method Summary collapse
-
#initialize(combine:, single_cell_array_val:, size:, identity:) ⇒ SegmentTreeTemplate
constructor
Construct a concrete instance of a Segment Tree.
-
#query_on(left, right) ⇒ Object
The desired value (max, sum, etc.) on the subinterval left..right.
-
#update_at(idx) ⇒ Object
Update the value in the underlying array at the given idx.
Constructor Details
#initialize(combine:, single_cell_array_val:, size:, identity:) ⇒ SegmentTreeTemplate
Construct a concrete instance of a Segment Tree. See details at the links above for the underlying concepts here.
39 40 41 42 43 44 45 46 47 |
# File 'lib/data_structures_rmolinari/segment_tree_template.rb', line 39 def initialize(combine:, single_cell_array_val:, size:, identity:) @combine = combine @single_cell_array_val = single_cell_array_val @size = size @identity = identity @tree = [] build(root, 0, @size - 1) end |
Instance Method Details
#query_on(left, right) ⇒ Object
The desired value (max, sum, etc.) on the subinterval left..right. The type of the return value depends on the concrete instance of the segment tree. We return the identity element provided at construction time if the interval is empty.
55 56 57 58 59 60 61 |
# File 'lib/data_structures_rmolinari/segment_tree_template.rb', line 55 def query_on(left, right) raise DataError, "Bad query interval #{left}..#{right}" if left.negative? || right >= @size return @identity if left > right # empty interval determine_val(root, left, right, 0, @size - 1) end |
#update_at(idx) ⇒ Object
Update the value in the underlying array at the given idx
Note that we don’t need the updated value itself. We get that by calling the lambda single_cell_array_val supplied at construction.
69 70 71 72 73 |
# File 'lib/data_structures_rmolinari/segment_tree_template.rb', line 69 def update_at(idx) raise DataError, 'Cannot update an index outside the initial range of the underlying data' unless (0...@size).cover?(idx) update_val_at(idx, root, 0, @size - 1) end |