From 920230e005e40fc473296225d5508eeba03adece Mon Sep 17 00:00:00 2001 From: 4ndrelim Date: Tue, 26 Mar 2024 06:56:07 +0800 Subject: [PATCH 1/6] feat: Implement segment tree --- .../java/dataStructures/segmentTree/README.md | 0 .../segmentTree/SegmentTree.java | 103 ++++++++++++++++++ 2 files changed, 103 insertions(+) create mode 100644 src/main/java/dataStructures/segmentTree/README.md create mode 100644 src/main/java/dataStructures/segmentTree/SegmentTree.java diff --git a/src/main/java/dataStructures/segmentTree/README.md b/src/main/java/dataStructures/segmentTree/README.md new file mode 100644 index 00000000..e69de29b diff --git a/src/main/java/dataStructures/segmentTree/SegmentTree.java b/src/main/java/dataStructures/segmentTree/SegmentTree.java new file mode 100644 index 00000000..45b73b42 --- /dev/null +++ b/src/main/java/dataStructures/segmentTree/SegmentTree.java @@ -0,0 +1,103 @@ +package dataStructures.segmentTree; + +public class SegmentTree { + private SegmentTreeNode root; + private int[] array; + + private class SegmentTreeNode { + private SegmentTreeNode leftChild; // left child + private SegmentTreeNode rightChild; // right child + private int start; // start idx of range captured + private int end; // end idx of range captured + private int sum; // sum of all elements between start and end index inclusive + + /** + * Constructor + * @param leftChild + * @param rightChild + * @param start + * @param end + * @param sum + */ + public SegmentTreeNode(SegmentTreeNode leftChild, SegmentTreeNode rightChild, int start, int end, int sum) { + this.leftChild = leftChild; + this.rightChild = rightChild + this.start = start; + this.end = end; + this.sum = sum; + } + } + + public SegmentTree(int[] nums) { + root = buildTree(nums, 0, nums.length - 1); + array = nums; + } + + private SegmentTreeNode buildTree(int[] nums, int start, int end) { + if (start == end) { + return new SegmentTreeNode(null, null, start, end, nums[start]); + } + int mid = start + (end-start) / 2; + SegmentTreeNode left = buildTree(nums, start, mid); + SegmentTreeNode right = buildTree(nums, mid + 1, end); + return new SegmentTreeNode(left, right, start, end, left.sum + right.sum); + } + + /** + * Queries the sum of all values in the specified range. + * @param leftEnd + * @param rightEnd + * @return the sum. + */ + public int query(int leftEnd, int rightEnd) { + return query(root, leftEnd, rightEnd); + } + + private int query(SegmentTreeNode node, int leftEnd, int rightEnd) { + // this is the case when: + // start end + // range query: ^ ^ --> so simply capture the sum at this node! + if (leftEnd <= node.start && node.end <= rightEnd) { + return node.sum; + } + int rangeSum = 0; + int mid = node.start + (node.end - node.start) / 2; + // Consider the 3 possible kinds of range queries + // start mid end + // poss 1: ^ ^ + // poss 2: ^ ^ + // poss 3: ^ ^ + if (leftEnd <= mid) { + rangeSum += query(node.leftChild, leftEnd, Math.min(rightEnd, mid)); // poss1 / poss2 + } + if (mid + 1 <= rightEnd) { + rangeSum += query(node.rightChild, Math.max(leftEnd, mid + 1), rightEnd); // poss2 / poss2 + } + return rangeSum; + } + + /** + * Updates the segment tree based on updates to the array at the specified index with the specified value. + * @param idx + * @param val + */ + public void update(int idx, int val) { + if (idx > array.length) { + return; + } + update(root, idx, val); + } + + private void update(SegmentTreeNode node, int idx, int val) { + if (node.start == node.end && node.start == idx) { + node.sum = val; // previously, node held a single value; now updated + } + int mid = node.start + (node.end - node.start) / 2; + if (idx <= mid) { + update(node.leftChild, idx, val); + } else { + update(node.rightChild, idx, val); + } + node.sum = node.leftChild.sum + node.rightChild.sum; // propagate updates up + } +} From 240a2c233d156d8c1f5ac1078d3c9cb148c500cb Mon Sep 17 00:00:00 2001 From: 4ndrelim Date: Thu, 28 Mar 2024 03:16:17 +0800 Subject: [PATCH 2/6] feat: Complete implementation and testing of segment tree --- .../java/dataStructures/segmentTree/README.md | 1 + .../segmentTree/SegmentTree.java | 21 +++++++--- .../segmentTree/SegmentTreeTest.java | 39 +++++++++++++++++++ 3 files changed, 56 insertions(+), 5 deletions(-) create mode 100644 src/test/java/dataStructures/segmentTree/SegmentTreeTest.java diff --git a/src/main/java/dataStructures/segmentTree/README.md b/src/main/java/dataStructures/segmentTree/README.md index e69de29b..f5277c0e 100644 --- a/src/main/java/dataStructures/segmentTree/README.md +++ b/src/main/java/dataStructures/segmentTree/README.md @@ -0,0 +1 @@ +# Segment Tree \ No newline at end of file diff --git a/src/main/java/dataStructures/segmentTree/SegmentTree.java b/src/main/java/dataStructures/segmentTree/SegmentTree.java index 45b73b42..ca361d42 100644 --- a/src/main/java/dataStructures/segmentTree/SegmentTree.java +++ b/src/main/java/dataStructures/segmentTree/SegmentTree.java @@ -1,9 +1,15 @@ package dataStructures.segmentTree; +/** + * Implementation of a Segment Tree. Uses SegmentTreeNode as a helper node class. + */ public class SegmentTree { private SegmentTreeNode root; private int[] array; + /** + * Helper node class. Used internally. + */ private class SegmentTreeNode { private SegmentTreeNode leftChild; // left child private SegmentTreeNode rightChild; // right child @@ -21,13 +27,17 @@ private class SegmentTreeNode { */ public SegmentTreeNode(SegmentTreeNode leftChild, SegmentTreeNode rightChild, int start, int end, int sum) { this.leftChild = leftChild; - this.rightChild = rightChild + this.rightChild = rightChild; this.start = start; this.end = end; this.sum = sum; } } + /** + * Constructor. + * @param nums + */ public SegmentTree(int[] nums) { root = buildTree(nums, 0, nums.length - 1); array = nums; @@ -37,7 +47,7 @@ private SegmentTreeNode buildTree(int[] nums, int start, int end) { if (start == end) { return new SegmentTreeNode(null, null, start, end, nums[start]); } - int mid = start + (end-start) / 2; + int mid = start + (end - start) / 2; SegmentTreeNode left = buildTree(nums, start, mid); SegmentTreeNode right = buildTree(nums, mid + 1, end); return new SegmentTreeNode(left, right, start, end, left.sum + right.sum); @@ -68,10 +78,10 @@ private int query(SegmentTreeNode node, int leftEnd, int rightEnd) { // poss 2: ^ ^ // poss 3: ^ ^ if (leftEnd <= mid) { - rangeSum += query(node.leftChild, leftEnd, Math.min(rightEnd, mid)); // poss1 / poss2 + rangeSum += query(node.leftChild, leftEnd, Math.min(rightEnd, mid)); // poss1 or poss2 } if (mid + 1 <= rightEnd) { - rangeSum += query(node.rightChild, Math.max(leftEnd, mid + 1), rightEnd); // poss2 / poss2 + rangeSum += query(node.rightChild, Math.max(leftEnd, mid + 1), rightEnd); // poss2 or poss3 } return rangeSum; } @@ -91,6 +101,7 @@ public void update(int idx, int val) { private void update(SegmentTreeNode node, int idx, int val) { if (node.start == node.end && node.start == idx) { node.sum = val; // previously, node held a single value; now updated + return; } int mid = node.start + (node.end - node.start) / 2; if (idx <= mid) { @@ -98,6 +109,6 @@ private void update(SegmentTreeNode node, int idx, int val) { } else { update(node.rightChild, idx, val); } - node.sum = node.leftChild.sum + node.rightChild.sum; // propagate updates up + node.sum = node.leftChild.sum + node.rightChild.sum; // propagate updates up } } diff --git a/src/test/java/dataStructures/segmentTree/SegmentTreeTest.java b/src/test/java/dataStructures/segmentTree/SegmentTreeTest.java new file mode 100644 index 00000000..d187c56b --- /dev/null +++ b/src/test/java/dataStructures/segmentTree/SegmentTreeTest.java @@ -0,0 +1,39 @@ +package dataStructures.segmentTree; +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +public class SegmentTreeTest { + @Test + public void construct_shouldConstructSegmentTree() { + int[] arr1 = new int[] {7, 77, 37, 67, 33, 73, 13, 2, 7, 17, 87, 53}; + SegmentTree tree1 = new SegmentTree(arr1); + assertEquals(arr1[1] + arr1[2] + arr1[3], tree1.query(1, 3)); + assertEquals(arr1[4] + arr1[5] + arr1[6] + arr1[7], tree1.query(4, 7)); + int sum1 = 0; + for (int i = 0; i < arr1.length; i++) { + sum1 += arr1[i]; + } + assertEquals(sum1, tree1.query(0, arr1.length - 1)); + + + int[] arr2 = new int[] {7, -77, 37, 67, -33, 0, 73, -13, 2, -7, 17, 0, -87, 53, 0}; // some negatives and 0s + SegmentTree tree2 = new SegmentTree(arr1); + assertEquals(arr1[1] + arr1[2] + arr1[3], tree2.query(1, 3)); + assertEquals(arr1[4] + arr1[5] + arr1[6] + arr1[7], tree2.query(4, 7)); + int sum2 = 0; + for (int i = 0; i < arr1.length; i++) { + sum2 += arr1[i]; + } + assertEquals(sum2, tree2.query(0, arr1.length - 1)); + } + + @Test + public void update_shouldUpdateSegmentTree() { + int[] arr = new int[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + SegmentTree tree = new SegmentTree(arr); + assertEquals(55, tree.query(0, 10)); + tree.update(5, 55); + assertEquals(105, tree.query(0, 10)); + } +} From fa96c707750d9a9891102aa259eb7620d6900f7a Mon Sep 17 00:00:00 2001 From: 4ndrelim Date: Thu, 28 Mar 2024 04:06:47 +0800 Subject: [PATCH 3/6] feat: Implement array-based version of Segment Tree for fun --- src/main/java/dataStructures/heap/README.md | 14 +++ .../segmentTree/SegmentTree.java | 1 + .../arrayRepresentation/SegmentTree.java | 105 ++++++++++++++++++ .../arrayRepresentation/SegmentTreeTest.java | 42 +++++++ 4 files changed, 162 insertions(+) create mode 100644 src/main/java/dataStructures/segmentTree/arrayRepresentation/SegmentTree.java create mode 100644 src/test/java/dataStructures/segmentTree/arrayRepresentation/SegmentTreeTest.java diff --git a/src/main/java/dataStructures/heap/README.md b/src/main/java/dataStructures/heap/README.md index 7ac53e1d..1f09cd76 100644 --- a/src/main/java/dataStructures/heap/README.md +++ b/src/main/java/dataStructures/heap/README.md @@ -27,6 +27,20 @@ That said, in practice, the array-based implementation of a heap often provides former, in cache efficiency and memory locality. This is due to its contiguous memory layout. As such, the implementation shown here is a 0-indexed array-based heap. +#### Obtain index representing child nodes +Suppose the parent node is captured at index *i* of the array (1-indexed). +**1-indexed**:
+Left Child: *i* x 2
+Right Child: *i* x 2 + 1
+ +The 1-indexed calculation is intuitive. So, when dealing with 0-indexed representation (as in our implementation), +one option is to convert 0-indexed to 1-indexed representation, do the above calculations, and revert.
+(Note: Now, we assume parent node is captured at index *i* (0-indexed)) + +**0-indexed**:
+Left Child: (*i* + 1) x 2 - 1 = *i* x 2 + 1
+Right Child: (*i* + 1) x 2 + 1 - 1 = *i* x 2 + 2
+ ### Relevance of increaseKey and decreaseKey operations The decision not to include explicit "decrease key" and "increase key" operations in the standard implementations of diff --git a/src/main/java/dataStructures/segmentTree/SegmentTree.java b/src/main/java/dataStructures/segmentTree/SegmentTree.java index ca361d42..77e9955c 100644 --- a/src/main/java/dataStructures/segmentTree/SegmentTree.java +++ b/src/main/java/dataStructures/segmentTree/SegmentTree.java @@ -95,6 +95,7 @@ public void update(int idx, int val) { if (idx > array.length) { return; } + array[idx] = val; update(root, idx, val); } diff --git a/src/main/java/dataStructures/segmentTree/arrayRepresentation/SegmentTree.java b/src/main/java/dataStructures/segmentTree/arrayRepresentation/SegmentTree.java new file mode 100644 index 00000000..0ce95d23 --- /dev/null +++ b/src/main/java/dataStructures/segmentTree/arrayRepresentation/SegmentTree.java @@ -0,0 +1,105 @@ +package dataStructures.segmentTree.arrayRepresentation; + +/** + * Array-based implementation of a Segment Tree. + */ +public class SegmentTree { + private int[] tree; + private int[] array; + + /** + * Constructor. + * @param nums + */ + public SegmentTree(int[] nums) { + tree = new int[4 * nums.length]; // Need to account for up to 4n nodes. + array = nums; + buildTree(nums, 0, nums.length - 1, 0); + } + + /** + * Builds the tree from the given array of numbers. + * Unlikely before where we capture child nodes in the helper node class, here we capture position of child nodes + * in the array-representation of the tree with an additional variable. + * @param nums + * @param start + * @param end + * @param idx tells us which index of the tree array we are at. + */ + private void buildTree(int[] nums, int start, int end, int idx) { + // recall, each node is a position in the array + // explicitly track which position in the array to fill with idx variable + if (start == end) { + tree[idx] = nums[start]; + return; + } + int mid = start + (end - start) / 2; + int idxLeftChild = (idx + 1) * 2 - 1; // convert from 0-based to 1-based, do computation, then revert + buildTree(nums, start, mid, idxLeftChild); + int idxRightChild = (idx + 1) * 2 + 1 - 1; // convert from 0-based to 1-based, do computation, then revert + buildTree(nums, mid + 1, end, idxRightChild); + tree[idx] = tree[idxLeftChild] + tree[idxRightChild]; + } + + /** + * Queries the sum of all values in the specified range. + * @param leftEnd + * @param rightEnd + * @return the sum. + */ + public int query(int leftEnd, int rightEnd) { + return query(0, 0, array.length - 1, leftEnd, rightEnd); + } + + private int query(int nodeIdx, int startRange, int endRange, int leftEnd, int rightEnd) { + // this is the case when: + // start end + // range query: ^ ^ --> so simply capture the sum at this node! + if (leftEnd <= startRange && endRange <= rightEnd) { + return tree[nodeIdx]; + } + int rangeSum = 0; + int mid = startRange + (endRange - startRange) / 2; + // Consider the 3 possible kinds of range queries + // start mid end + // poss 1: ^ ^ + // poss 2: ^ ^ + // poss 3: ^ ^ + if (leftEnd <= mid) { + int idxLeftChild = (nodeIdx + 1) * 2 - 1; + rangeSum += query(idxLeftChild, startRange, mid, leftEnd, Math.min(rightEnd, mid)); + } + if (mid + 1 <= rightEnd) { + int idxRightChild = (nodeIdx + 1) * 2 + 1 - 1; + rangeSum += query(idxRightChild, mid + 1, endRange, Math.max(leftEnd, mid + 1), rightEnd); + } + return rangeSum; + } + + /** + * Updates the segment tree based on updates to the array at the specified index with the specified value. + * @param idx + * @param val + */ + public void update(int idx, int val) { + if (idx > array.length) { + return; + } + array[idx] = val; + update(0, 0, array.length - 1, idx, val); + } + + private void update(int nodeIdx, int startRange, int endRange, int idx, int val) { + if (startRange == endRange) { + tree[nodeIdx] = val; + return; + } + int mid = startRange + (endRange - startRange) / 2; + if (idx <= mid) { + update(nodeIdx * 2 + 1, startRange, mid, idx, val); + } else { + update(nodeIdx * 2 + 2, mid + 1, endRange, idx, val); + } + tree[nodeIdx] = tree[nodeIdx * 2 + 1] + tree[nodeIdx * 2 + 2]; + } +} diff --git a/src/test/java/dataStructures/segmentTree/arrayRepresentation/SegmentTreeTest.java b/src/test/java/dataStructures/segmentTree/arrayRepresentation/SegmentTreeTest.java new file mode 100644 index 00000000..132201b8 --- /dev/null +++ b/src/test/java/dataStructures/segmentTree/arrayRepresentation/SegmentTreeTest.java @@ -0,0 +1,42 @@ +package dataStructures.segmentTree.arrayRepresentation; +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +/** + * This file is essentially duplicated from the parent. + */ +public class SegmentTreeTest { + @Test + public void construct_shouldConstructSegmentTree() { + int[] arr1 = new int[] {7, 77, 37, 67, 33, 73, 13, 2, 7, 17, 87, 53}; + SegmentTree tree1 = new SegmentTree(arr1); + assertEquals(arr1[1] + arr1[2] + arr1[3], tree1.query(1, 3)); + assertEquals(arr1[4] + arr1[5] + arr1[6] + arr1[7], tree1.query(4, 7)); + int sum1 = 0; + for (int i = 0; i < arr1.length; i++) { + sum1 += arr1[i]; + } + assertEquals(sum1, tree1.query(0, arr1.length - 1)); + + + int[] arr2 = new int[] {7, -77, 37, 67, -33, 0, 73, -13, 2, -7, 17, 0, -87, 53, 0}; // some negatives and 0s + SegmentTree tree2 = new SegmentTree(arr1); + assertEquals(arr1[1] + arr1[2] + arr1[3], tree2.query(1, 3)); + assertEquals(arr1[4] + arr1[5] + arr1[6] + arr1[7], tree2.query(4, 7)); + int sum2 = 0; + for (int i = 0; i < arr1.length; i++) { + sum2 += arr1[i]; + } + assertEquals(sum2, tree2.query(0, arr1.length - 1)); + } + + @Test + public void update_shouldUpdateSegmentTree() { + int[] arr = new int[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + SegmentTree tree = new SegmentTree(arr); + assertEquals(55, tree.query(0, 10)); + tree.update(5, 55); + assertEquals(105, tree.query(0, 10)); + } +} From ac2b7267b40f3cf86e2642a9238c9460858ed27b Mon Sep 17 00:00:00 2001 From: 4ndrelim Date: Thu, 28 Mar 2024 04:31:52 +0800 Subject: [PATCH 4/6] docs: Update README for segment tree --- .../java/dataStructures/segmentTree/README.md | 88 ++++++++++++++++++- 1 file changed, 87 insertions(+), 1 deletion(-) diff --git a/src/main/java/dataStructures/segmentTree/README.md b/src/main/java/dataStructures/segmentTree/README.md index f5277c0e..50ee9706 100644 --- a/src/main/java/dataStructures/segmentTree/README.md +++ b/src/main/java/dataStructures/segmentTree/README.md @@ -1 +1,87 @@ -# Segment Tree \ No newline at end of file +# Segment Tree + +## Background +Segment Trees are primarily used to solve problems that require answers to queries on intervals of an array +with the possibility of modifying the array elements. +These queries could be finding the sum, minimum, or maximum in a subarray, or similar aggregated results. + +### Structure +(Note: See below for a brief description of the array-based implementation of a segment tree) + +A Segment Tree for an array of size *n* is a binary tree that stores information about segments of the array. +Each node in the tree represents an interval of the array, with the root representing the entire array. +The structure satisfies the following properties: +1. Leaf Nodes: Each leaf node represents a single element of the array. +2. Internal Nodes: Each internal node represents the sum of the values of its children +(which captures the segment of the array). Summing up, this node captures the whole segment. +3. Height: The height of the Segment Tree is O(log *n*), making queries and updates efficient. + +## Complexity Analysis +**Time**: O(log(n)) in general for query and update operations, +except construction which takes O(nlogn) + +**Space**: O(n), note for an array-based implementation, the array created should have size 4n (explained later) + +where n is the number of elements in the array. + +## Operations +### Construction +The construction of a Segment Tree starts with the root node representing the entire array and +recursively dividing the array into two halves until each segment is reduced to a single element. +This process is a divide-and-conquer strategy: +1. Base Case: If the current segment of the array is reduced to a single element, create a leaf node. +2. Recursive Case: Otherwise, split the array segment into two halves, construct the left and right children, +and then merge their results to build the parent node. + +This takes O(nlogn). logn in depth, and will visit each leaf node (number of leaf nodes could be roughly 2n) once. + +### Querying +To query an interval, say to find the sum of elements in the interval (L, R), +the tree is traversed starting from the root: +1. If the current node's segment is completely within (L, R), its value is part of the answer. +2. If the current node's segment is completely outside (L, R), it is ignored. +3. If the current node's segment partially overlaps with (L, R), the query is recursively applied to its children. + +This approach ensures that each level of the tree is visited only once, time complexity of O(logn). + +### Updating +Updating an element involves changing the value of a leaf node and then propagating this change up to the root +to ensure the tree reflects the updated array. +This is done by traversing the path from the leaf node to the root +and updating each node along this path (update parent to the sum of its children). + +This can be done in O(logn). + +## Array-based Segment Tree +The array-based implementation of a Segment Tree is an efficient way to represent the tree in memory, especially +since a Segment Tree is a complete binary tree. +This method utilizes a simple array where each element of the array corresponds to a node in the tree, +including both leaves and internal nodes. + +### Why 4n space +The size of the array needed to represent a Segment Tree for an array of size *n* is 2*2^ceil(log2(*n*)) - 1. +We do 2^(ceil(log2(*n*))) because *n* might not be a perfect power of 2, +**so we expand the array size to the next power of 2**. +This adjustment ensures that each level of the tree is fully filled except possibly for the last level, +which is filled from left to right. + +**BUT**, 2^(ceil(log2(*n*))) seems overly-complex. To ensure we have sufficient space, we can just consider 2*n +because 2*n >= 2^(ceil(log2(*n*))). +Now, these 2n nodes can be thought of as the 'leaf' nodes (or more precisely, an upper-bound). To account for the +intermediate nodes, we use the property that for a complete binary that is fully filled, the number of leaf nodes += number of intermediate nodes (recall: sum i -> 0 to n-1 of 2^i = 2^n). So we create an array of size 2n * 2 = 4n to +guarantee we can house the entire segment tree. + +### Obtain index representing child nodes +Suppose the parent node is captured at index *i* of the array (1-indexed). +**1-indexed**:
+Left Child: *i* x 2
+Right Child: *i* x 2 + 1
+ +The 1-indexed calculation is intuitive. So, when dealing with 0-indexed representation (as in our implementation), +one option is to convert 0-indexed to 1-indexed representation, do the above calculations, and revert.
+(Note: Now, we assume parent node is captured at index *i* (0-indexed)) + +**0-indexed**:
+Left Child: (*i* + 1) x 2 - 1 = *i* x 2 + 1
+Right Child: (*i* + 1) x 2 + 1 - 1 = *i* x 2 + 2
From 313120f419ecf2ee820cef28696e33b1bad6e9e8 Mon Sep 17 00:00:00 2001 From: 4ndrelim Date: Thu, 28 Mar 2024 04:46:36 +0800 Subject: [PATCH 5/6] docs: add segment tree image --- README.md | 2 ++ docs/assets/images/SegmentTree.png | Bin 0 -> 29558 bytes .../java/dataStructures/segmentTree/README.md | 2 ++ 3 files changed, 4 insertions(+) create mode 100644 docs/assets/images/SegmentTree.png diff --git a/README.md b/README.md index 5fbf1829..c5e35a64 100644 --- a/README.md +++ b/README.md @@ -38,6 +38,7 @@ Gradle is used for development. - [Monotonic Queue](src/main/java/dataStructures/queue/monotonicQueue) - Segment Tree - [Stack](src/main/java/dataStructures/stack) +- [Segment Tree](src/main/java/dataStructures/segmentTree) - [Trie](src/main/java/dataStructures/trie) ## Algorithms @@ -86,6 +87,7 @@ Gradle is used for development. * [AVL-tree](src/main/java/dataStructures/avlTree) * [Trie](src/main/java/dataStructures/trie) * [B-Tree](src/main/java/dataStructures/bTree) + * [Segment Tree](src/main/java/dataStructures/segmentTree) (Not covered in CS2040s but useful!) * Red-Black Tree (Not covered in CS2040s but useful!) * Orthogonal Range Searching (**WIP**) * Interval Trees (**WIP**) diff --git a/docs/assets/images/SegmentTree.png b/docs/assets/images/SegmentTree.png new file mode 100644 index 0000000000000000000000000000000000000000..44517df16f4870d83204c10caca34498ee1843a5 GIT binary patch literal 29558 zcmaI8bySpJ^e#Shmvom%C?VY)QZh(42nf>M9U`qDAR#F*f`kf4Gk}1I^bpb^-QDmz zkBVmD-T$>|IG32!siuswk)Hm$Nqjx`+6RZtA<0ovvp`keyshVGH zee8UXLUQdGe(t{emfE`=I1so>M=X!MCy43;DS?>ahRug5&IfxjM}ZG-g5wUtb=~_M zTd&sTv9%5BhcSrd(Ob}q@SqX0ym`bdKNM-qAk2#P8?#L!R#sN8=jk)r}4L z=mJ)pO632{UiTFqV>4fG4$9ow>`c|(fAC=Bo1Io+QBlQSh0(WHGI!UhuLx*8dgy(L z87enJAEd^v^ksPNFUX1eY(FX2uW06!H?idBV|A&n z2ObCyVd}{4`1i8)k^_3F4>UDoZjMuXZTK?@>BVhOH3Cn!AFr&gW`S4JR7qwK%G7u; zdNv>G8kdkDXlrMeeY*X}y3DlUE2oUiJh(|?Yoba-uT1yT&*gf)0X<4xCffs?p?fg= zM{b7~m_@4`+xBNu=tpf+!_U?-&sd{4x<0O`VK0h++tyaIT`?C%iq#dBl-|C7|HQ`T zKD$=#N1vUk@v}0$a%C?s!Rb2ZBKc_CaWbn&OoDp91D2j-#))#n*>Gn##sVgj@zL!g zOLi{kw|dm|cx%UWVtEL1A+KR-X*pdaxLS;6GwXQD6pD z4B*vP)`yD-ufQv;Gcj;fUx^Vs@v>@i4QGWn!D{k}cicayNAmScpJU9x*I&#V1{2n$oV+{BhpC)yi-kmKpwDHoMB%0aT$>7iGjI)G`C6J z{)js7+qATAL>bl59WR=#+qM>Ycm+QVp<&hn7Yf!1$7`g6Mn(70 zPleu`7>uG3Nm|}qH0`wt>`Z?jM6QuV=uPd*>+^&0vl5NW=f8gc_L>ZtZS*cFuWFro zmy)v7|D%73aHk^tEZiOLy*jaqn%+ac2f0OUg_LDwFowm1ZOAG$1taaDSio);MciRF zZ#l8Y!ONTc8hfpXM9_KaT@t;-NWL5zWc7DuC)fzDU%$=|IN1d66oE_5^(HTGup=7p zPosCa_q1(a`eW;E{1?C9%N47o#Xb5ROUhou*~tkf^^x&KnL=?TJIc&LH9(1vGh#>m zIni8)?T0=lW{$0`rkV#fr^VmZ)sdD!Ur0)7D#|+8@L-><{mvA?XOzx~h(O&6RCtB| z#ic3W!~uA)QH?!`l~p4GClKu_Y|m}m(^flu3GJa9{^v?a0A%NcBL`_ZHIa?C9{L%D?j%@nDPMa6SyP`EZuG6&Z}n9Pv()o8$k84DD(E79i<< z{XOJD488TTr<7kW1HRF?Cm<%4d3@|uSXlTvF_BGJIQ{*5s?tvWzbh*nAwkShZZYTv z^4Mnd;$A=Pt_J%1*#rbe?XD>0v8A4X(6m^=s!W-Wu9CnLMqKFiHXXeF_c_HxXb3%Y zp!vtLU+80$KeCPfs%RcFqRM(lkDt#zGI`*DI1aLuswNN`0Mj~8NVxwfYF|-|35UFX z#@>8sdu|Z@RuMyx_V?Z9e_T2>F!R|18E+i+Q;qCd80ZsH4r&xd1d5c zfQU;8!a6p0B|2_QSY9;-S}W~|fL|KfoAkf<)fgt#wK!+5a={Vv7hGgYSmTvcVioSpX(`pF z7)E^ZKDT=kHBy3KCe(KrXdknz0AU*@MEQa#TH*?9r;L0xxc*2r>eTJCP-0O9mUj;p zWd)qtN>62_M9!Go)S2a@fRmsT?u5M;LDAcu%NS2ucs2qrXB)1Q|3wU@i36s|_f*mi zt&1qOntr2{l&hxAb?2QN+uK{u|Ngq4mtxFcqxJqK=~AA&Ky~`rA8H}FS_vC$Y-ZFq zVDR%-K2M?uWzG7<54$*OYJ#`37UzN+Ym$u~D9XM8Ya47IqgYS!q&m<-`Gg`D_KF6z z5LT+7es8mA2an_pc<&AYw&0E4Ag>NeHQXijd)r5fxFlrA&xP2E9q-e#CM>93Hr$^& zK6XJqvzY~Kndmgcu%X2L4qiA(TRQZ0p}z$B4;lCir-`!{HcZCMGstV$WLT;`G}=hL z*Y79KK^dEVWhk@h{q{7DM76R%j*h$h8Yy|oy_g*%T7oy)YjfIx( zq%Jub-`ntHQEN&mG2)6n79;COLN{PRyb~;_l;mbp>{ZKRYQ8^JYHN#)tzGuSjV;2= zAMpk|-Pjk4se3oLp%-sa3al=D7_N&G?{ahOGo^@!Bu+Iq#m1}(EZB>#Q(l4W`E}V> zZ@ikZjld&iOIpHxF&+N2RP7ix5sGflv*0rSRx3Myrzr8gMDhtsL^^o-n|El&&%8F} zuAZD@E)?eVaYVT#3fu1O5))4`L&s4vym*R;rJ38)_?~$$h&zeQ3Cq5lz2by1lZ41) z3Xri(DxpkR;?=oyA6TWP*qfA1psIL-I~u_no$IJ32RdG<--I8x6SL?>qZt$#!=^Lu zD)hD~qS?^c!=+%-rmY^B?_Wvcvm%X0mAE6TNB6vMoQcoHZc#jx z^raU{R6$2rwQ;S(!MKU*#a{?Wxvq}}Wpt~|KkVc(8e{4Mf8$T5y?zIzRLl zClar(kfJC?Je1SW!0*ozI{I^KQe(e(*l1GcbYLVFMci%;4ok1~p@JVL1G!S_E5FiW zUk|lOkJmaH5Hd)@u0oX7Q-OyvE5cPZG(LvhT(VWJ{SwcOi;Ls(XJgKJ^Wy3Ml+XoN zD)QB1)Kdt#E(8(P-HABZtkc7B>H9#$Z(#|43|n++mCN(jEDBQz^E;9*772a>!W?>J zQ&{38YB|+{kEKj>PwvZDn)(`ukinvhCEFXkV-*m5)DmZAOf7uWl2I`WN_KwnwfUeq zKv(mitUZoh`N{=%)7PF-2&TTbF#l(v=q0F(DE)61xa>jLHU0W>^ntMRl%k)XD9C)Q zLEb0$as)lBSUuybbr0dad-u+-_S*a}Rx&<8<@&!%f@E-HbW|+#Rx*RfY$?sayg(z9 zKbOoZX7;YMP}waM|6KlP4h=>!&x_)Vrj=zezt<}lP29eGeQ_k{GV^|Y-JYMHpD$Cx zw9zZ}=g%kOpN%>TmEvL00@S_?-nC95nUBF&r*jO4e0A_m9$mZ(n*}U{mo$dY)-5d+ z)+4M(Xn3benv102+*AT6Sk2t;`GAKPD!zRAQu6Nl==yv)Sy54u&vRA7JoLsJnHO}$ zQ(mkWB^v@KSX^Ax$d$~D#-rr7`AIxpY1Ws{ZQ^%#bB032Z-Z?SbbtY}h@%owO>LbG zI{Dd;$|ywBEq6E$9us`J+=s3^gi*u=8z6s^yggq|pqEJh{Q1$Zcbp0!g)}lUI^LQ{ zW>rZdrlnOkHKp5YJ|YC8ADzBA^~^Izd8cw>J22FYRff?*0Uh40je|?fQOKh+Yz*Ky#bmjZk_fKCIOgf59uW*~)4-LTpcC5=n(pTB^#Gb%cIxYA4lY_iV3y{W3|>dPk+ z786(d&f)W6MsSve2f8w4OU(|q--R5Wucrr4s!=HzS4NqHT&z$&)6t=S76_~}GSKO44#tlxgBhSRLki&;o$tg#I*n%c%~b@AA&k-spV{rRa~4VER|jB5G2u$eYOpy@2)-h z1qA$$`bFsLvZaH?YaJ(EEWpD9$gJ5nIX`g0UK|r?ixg*08b4>mXdPd+1d+{}KNGx^ z$a_93RMH0;mSbgl5Clv+a&pqJqqEb0w_#1xa}~es`Y_(Rsm^)&a7cmZap-MO`Xi%` z@d}fZN8=$2;<|0+xbPSGB141MA%bOt_M`|Y`~`vhdwh`hh5u&F&0*^C_b16}e|C?F zYl{+a-m9~{Qjj)&Hm;5P`0>8u{3{YxWxf}`skVILDS01&?D6*I3eE8Q(MY7MuO*KI zESgWZze>2Q=xQD|RYc5!9vvMGO2nDx6R}B25BT{@YZ~B7xP;tG>K;7 zm${A>(W5AALQsMT#SoQ$krZ*7lm%0IqNdhi!~ex=nWB3Bsz8 z_cpiK{d=RkQ2xBGjsE1_qDU^CDRQsSOLR-@HFw^e%@1yll^cDv!2$2P3}6Lh*kV&p z9|FaW&-P?Hc#z%B+(Ln=Zakt0{(K=S)qA|5VbC6dy%VE-qptL3q*hZG{R0P6sa5Bz z>-oEzJOhbey}c;=r!Ts|M0-I^3faUw$~2H5l}AtQ2}|adL9YI^OH=>O2OB%P)XYp( zd3pJQvzZnxA;-!U;Msr3$88QU4>BJao=_ym+F z{|`_D1iL6=mWAJWGI`F^b>vM?jg4sn&vuJn^k;#y+U$(qwBAkbEI4jNF5+Q32-4?! zp?6y&jipaNu!x9ch9ijIG#S*$90e&aYN)7 zCZqN;Y?l-9k;Cw>G4N6Aww|dmE5bOiYPy9j@|378Iox7Wo$FBVj9LBQEs&4(Z{@Dd|I3 zUNmEsV_b;v56ymqGZ#%PeJ>U_;H$Ps4u&i_{Tbt{vhb43vo;ia*zzqXb(jhLu*SZA zB={`+%)=McfDN_pjanXYhe{Sowzf#7I*jS3!6u4he~+3FqxuL!9y?4J7MoHlr$<;; zF5jEX(4=CrVL~K0bU`Km`dPP!^%qI8b2R8EQ4fKN(3V|ha#IR?`!`qAK9PE#KVdXl zIlb&dM#lNpk&Fn}hwtTI6YFE0GuBDtD+|VosCcUh6^Qo{9UmP;6L)`WBbwy(haFoc z7=%cTmVZ4&@yZ&n?#2Uq-4fbR ziFwPHvHWOgG~WZ8IpPO7{9e#>OuLSV<(8v6P5tQP5;k)XjHmilhnyY?AAyiyspEQN0f zEPZ}Z%8UBaxcr{5-Lk4_na}omMZ6BpK(>1MVEOO`@Ly2@Y8=VXESK5Vlm@a}~&gkS)C;G;$rC?qUW47TJ@=ID}Mz*YJxB?Z!p#I1eR#Bc-wS% zD76V4Giu7s-yc&efi~L@T6ED@nbM@0gH{79iNFpyRE*ubkE-rYHz2=?Mk?QcA*#HX z&qYcV9bgPy@4Hpq-+{5?1CXOSAvz@zyvldENzCW75JBYhsJIAw(mk(iS%-es7pCFH z!hL^Iy^{Ca;j$sKC>lc>&kw<(e$sFH?x_eQ5IE-wq>72V>9+7gumV@Ge7&5+-MeEe zK7COx*jJ5^7F?K>eQeZzG6$W>z)l9(&&zT8WxdT`B62HzuGtq9#wz13y zyP>0WyUO>9jcCJ=9=j&3H4UEjD*ef8h!FOZuJM?HFW`!&_E+$JEG}AO7UtvPn~^#T zLR5O-N^XT>`&e~q^APKJR>cJvW>EaG750PEVCYjcU!KN6J~o$p^bm z4rUtn{zS#Gs*#3^eI!!g8BGEN3H}RqJ|zL zUm@ks;1kQX9E<=OL!QMJlP`Lggedfhz{OfgV=hOyWgW;0euY%levoxUj;eF&`O+bS z{HKmxfjn0*%U?E>tGCkl#qH$q=X7gm@%%N4@{==|Ir(l-wq>^HO7qFf(_O{O(>P)# zE%$fk!C~>R`72jhQZSTSgP-n0WfTxfPh`=S;~reYTSwTnifNx&H6f+UMECdx{M`n<9~w2s*PhpcV>x?ZXirgwXkg6*uWZ$%i7e znubjf43+ai-Iv(p9KLy#4ts~QvcQFVPB#D4%7bl)Oo(Y-%#x_A4w_@LK%#rpj7_Lj zH1de;Q(_j{BRZj`8)0375z50bci3>P(n1rXP=ZQ+7DUn&up{aY5JogxHA7xPAzx=y zF8EyRW$s~G3!GGXrVX1o(S7c%0C9SD(0N1jZPN2=p=Brk&J0H5bqAJi3*Ij7zTmUr z=z&Y?>yu}QdwZRO^tvpGJYhu9C^H^?+#1=!{p?tPfM5qW?|Z5VhTndm^2`*lOR9BZ zv5)HN>iPo8m<)X$4h|-E_85>E=aH>~`qb`xf01bdL^*9LIH=I5A3u*8wnfRe8_ac@ zZ>9g6YeW94og4yC;9^j$D^sF{fuxGo41KX+e}6x$Aqms~FT6;iGEVpAwThGz@wpWM zFd!zzcJiD!oQs*6*>YF4QkV~5WXhDX$TWxL9e{5B2S8T7RUwerj~Isb8D%`6I+zGC z<5M1fx1rBP;xvUe3q`{S;Lm+VyFh_BH*NKA)<;iufZHPk%`FPM*N*g2-FTry@6oS| zI;E8?HxnB3wozM87u`1@v*DZQlcLTe9(qxurCO8$DXU9e@q{uKAZ1D}bq+xB{DPrB z79Qg+&8ti2@OPF(w(z313)a5qa$LvM5eS$eozkaov$IY9imwgk_1N$mg%14u$s{9_ z2a30+dD6(LM^fzA8?K6rrT;-&=lP^#Y?i7e2Or%!wi9Xz+L^zH+oH+E#RaHG8TMsZ zStC8ya+2{fb8>!zOifbChCH8SpP8#V4*jyQGE-d1NhiKzR7S7EhgV%0WA~*0iZUb} zkRiRP?0Bd;tBUfQA?CA)af(dztFq8#k5n$b&VAY$#R^vLK z3+NOIs|Eka1E3dSzQY}j5{sN=ZQvZ_^-Z|l{r1SUQe z98gycH>cAV2R)1xdx;EEQvpN{Gxd*;R{KYn-<(bi?!fsGEj`Z(tI34=emw85vx4iu zwP5pTRIVE<(`S?u4T{_dd5hyMRC{Fr??|Z)z46mY+X=T5cjf&A9i_=ZJg9 zK1CH36N}KRo$n2cuV|@+ou~lF@{Zdi9aQ;4A5}>~ z0UOh6^L%^q3&a#KP}jFtdte3UvJ2lsk0^3GF6g2y3RaE!zXv*#JCvoD&CwaITmSv} z_IkgQ2rTYvBwV=LwC91uH{3Q6oB*eAX)(BfWc0Ss54&AX(RkeY^lGLp^S4r(a4&u^!8qW)0LI~j?5f#UG*+Vn2oa!;}yFm!ZX zt*MT9ApUtmM>siv{Z`?NEaN07mdESEl2_Z`!f1YuKL;?KG;CM=(mz@ed8tPCLgMuXSD0$G40K<$| zsxw91^>vU1rar}#<09>mxzscb|(Z zZn#JVjcdQm)TlUG^8xA6+F&UthejZ<(SBJcOTD1~~=>OINC~(LmIk*#}{5IM*D^e!-`t_?H@DKm>f|&Eo@~YSI@o4#A7RTFvQURd3 z53sMrqyy35jWou135uDXTiXEsA`uL|zm;oPE_oHtuyrP?P&F#j^YDwVWYKd&lw5 z?oXDH$YYJm>=dQK?Vh}p6$+Qzl=hE+m$GGZSd^EBEdfG+;$EC~ZNtzlT~3y{eP7jj zSq5cnsjn9WAeaI`3_+P&2+k+n3ga|T-TLc9g+gx*H;W>Uv%>0(jTvBgbcd_5@{CwS z41dA>)weShCL&AA@p)(>l9D;6JJY1(T3%NE|jZZ}Kjq^(K8Gim*viVS0`AHYic@IV1xH89n{4+IRcdY^B>NHs$ z&TT>$y2coK{rKkU?5wLGRDQN*vxujT8uqj|eJ=V=u2$_>$s674_Wc{a-+;M2|C_3H zemd=1!HwhEb|Vb@5;@TL)7`v~OHQz)Y+PKw8s`Am+)M8}V-@_m1CLUBBilk-Zj70U zbnIo#EB_C2a28jh`^R4ZSX$>Y`wIYKf9jmG6>zIL$hma$6=Db_Z;nU3w#NI#i?XF~n zw_z)o1q6tHpAV6+?n$x*;B^9nR2B&9Z_?6~3=OG(YoH;5qFVyb#+MmB>S2&;m?hJs zpdl2D4q$@cim9D3H)+sL{=Q_*$J?~3dIiJsawru48CvMed~%=Lpo_yqf0p$TB?BA) zxs$bylmI3<>0&;Det07R8O#^IDlQU#tBmSezI=hDNKNn{`)k?V>hKjC_YVM$h}hA>6+Z{FXh+%HXa z{%gz+|KK~<3w|~ZPJs{BmJk7QyEEIh6-V~@a~5DbTY$agZjav@10fE50WOzNDp3$2 zzM|eS7lahr9%RIXHYR>q>p$zKJ5)7WwI4Yja+T;XR%Ub+l?3c#U=f@qU^f8$?qU|> z&C1Gp(u`&FPDP5|FszXxMOzE4q^L4RZ}sFw{ws^~zUF>D-HccEx?y*iT(3ikr%%vP z{4`bFY}o+@1oA+BzkN$2$6n_|4g8YugIuX*wsM|y@bPX`P85wIBC2sxf2zfR-~`)| zVN-iuFUz@)$=Z~9z=nUgREyC(_(bn%uB57*97GWQQ?aj(etmI5{{h z!4AC!+YIs9C>3D4hdbZrjq?hB_V!wJCr}eEN3L6*UJ6`^SJ;{GyuODbwEvABON4*o85h_v3_1_EJ-JUAq&g&fGhb}Ckir$9=M zK=?`pdK~wqA2`z2`wHT|yZA^24YgE&poGsh69{);q5MY@7e%>tM##s^+W%nhJe--a zL*0z+BtmAIBcF`~loM&X^5r7!5ik-^1lS%dbw$O*=(Gm;hXAz-$fIN%JXWYg-I##H z=kWARymtGUGprlMpg{tzPrqP{h@|My%7T;tWVh#IX>+q=@^^aapn8DLjdd+}vd(yZ zcKY*G++1nSsNSt$MLb}1os`v7nB+u40Hp*(JlbIDOr(^_$9AM8HE}-^C2XU1!d&3; z-dBgwlEf8pE(`fT>I54@yANa%Fjznx@tWzu|E1?ZYBWHpA&!(e{6kjx$s&Qa;!ogS ziwXc|dmlC~f?RNWsx}_vS~P<8(51`M)HpomWAelHF+dOa9S^IR8T$_AN&%_UaCL#> z@>{^#B!G1v`C9B~y;Nb*HdlP2xX?Q=;Bz4^9(*Z?Jc59~@(>7TXJ!4`oo#wKR+grI z)J8A;nLa}sJ$qxcG^06%xXZB7ixYSzUn3QSPR!#6fL&$EUeSD-BC}LSscT48beoJj zm`MC)Tf-|;Gc@*)Dzt^{yPy%J;8n?)y;ezm1>%QMh_jP9TYQJs9nb z3q5jGbzv7pC}@i5j;=?DzQvuv`7F@L)M4ANeU_MlQ0d>uh~Jvm&VQgBLLd}83~|zN zAYWr-;>#LQguf4uYn95h4Q%$GX2iL%)FZ2s*)*PvbQF;ebk;sn$yLI*U^!MSXx&yb z7B5_->Q~leT>2$^qD|Ubx;$CP*B!m{>+(5VgoOKQZR&eN7P8vfR!A`}a~99&sO6uCudj$Stz8jD#Bp2zA9R z6sU+p)xl-S$jgwowq6pZ9Ot|BY8p1;eE<;0Fhk{<|XJyzx0NxZ=J=G4gk+%b>S}h?HZ?^-+oc#%j0F z`m7!R6UiJdutnxT2nXzU1E+S=aw-j05lguIQU5 z_g5vteHaR!QHjdKy3r0@O8#%S2p> zk_rD!QWQh&-~GjkOu!V~z*j6up8R)pvaIUA_ozoV7Kc70epo245}y8VKsW3k|E7ax zk^kQsNuqN9TN`2u*nju7TEe1%3HC9-t-wRtnW6t#P5T@6%zw8UF#TI@s(Mr*dYB&C zlkUfG8XEvsw#aH>IbbMs>DDt3fqUMB<1@xhyBS$_8JLTv&jW%5Toxte@p`JW@ak6@#Rk!w`k z6;ido`}Zyj*sHV=V4#>_@qMnyz9m9%ce*7oAcnP)-Xu=lf3sEK5VTbf81ifX&j1V9 z;B$SB86EWsOHHJahWrYkeZch(BK|W3ocQyGY=z|j<~xV>9OQHI-Q_nhnKtB>(H;L; zq#O4XIfAaKdYUD8VK4$!!K4>(wL3iU2jJF;q}yNwXmii2&(MGCFmxyXMW5||U7$}@ zeNUC>(gX%}l{}{e@yMeMcyc1oYoaFsL!t8if>z*w(1u z6yWjm$m{f}_R*41#;;zba|lK|fNg;Ih;@>bMCvt{H%^u>!$&&d7~9+WFiC|g-=T?( z8m$@o8ueJ#>`iM*1g;^Pl4KdipusMNG|DO32dGGG%Ey8cr|`l@#5)}U6KD^i^eNK? zBT=m>v5spa7SF>)8F$+Vs~Nm2d@xTNsx>LfmdLPom1cFyY0QWdoh&i;fqMIK{EzQO zDNl4E)Az_fhpu!8`@;gCTpadEADcf>zu4Nk+wuU80vlFTt8ctH9mI@ma=)L5-ZnjScCL)sg zF7ed*`hvryVZfJhmV4{*t*Lzms;(OyM=Si?bIHknAcL_{G@y=95XFAD5My|_QWrLx z3TSVT_&))PB2%DNsmudXT)=OBUcn{SgwTk%XaoiIk{2NHx*SotL>i&j@uO|1F8rCG z@{~bdlo-AbNK$CA8hIYw0suiliTkQd&#b(9Z}LlIPEL-jxXMZRI!G2AfT#c{3o$T| za$um8g?@U*mPclPcYE`(xL8kN%=}xB2l1IM)~^g+i@9RYzp)@^Ncr$V^JH_(%=iw} zksm*Pe5XY4(rt!4+9TPO2lGZ(xDoO~lZBP_VxsNV)=LcHJqz+B(FAy-s|bqypRa5r zBy4s)I?tYo0^JZuF}z;}``X&rRQv9kJ2oWb2X5K|cmPphVz4*c=nSwQAnrx1KNl79 z-qdaM+Ia5u_-B9ri7M0Q7@$))00<7P8OW$7D*F$X!}rbB?Ez-eeDT84i+XFOLBMgM zQmBzC`aT;QQV&KAt~3wa5lZJVbMShcQ)b>G4g|^~HTa;AuF*Y3eF}=AKVNO*hr1vP zK$-j;C^VEQJ3j%j#xsyC7R9%BC(^#0sQgf1yKmb@0rD`pe7$mgz+ul1@oRh#PXjqU ztuZF^@se7P12Rj)US#?I#rywfN~ir2w^BU6`yq9bo%MkrW_Mvp365T0xNo?l)JzC* zHST(`Ni3=sdNr0G3T&(WlsrsDdqP{_CXO6>FYE(c00{DC^vH$6{tC+nmZiyrWgKj~ zAMnFF;g}1UQh4NHCD|DR($WLoFn1El%X86y@`TI4KpLTn3|<07&2{=G)=mx2sjAV1 znKixxx$bW3mCHTSmPVIfka_FuZ7~#b`{)AY zgfVGH3ko6Q-7|O|Y`A$Iwb5S(TMI~v4?q>+arjpi*>eCSPZfK?0F(Lq_pjTI)2-w@wn6j`-z^wTZDG;pxK_@qyO1ALAbI5w756^&EF5(5rWPKR}_$xBG1g<#~ zd^W3FuHSz-SD+Acz8J&Ep;Lk{6>wag^iUXRUOGCQNJ&4Il#J9ln^ZRbs<`kOM0IsE zcf>sYxbG#NTr{BPjew2jp^k=?yE{jD&jL^*E+>aBhFJ#}7uOIJk1<4ytBqTg%iXlD z$E(C7@OhZ*tT`_tD9Lf#JRT!NIdPZJ4YQu{9Q#QJoIOiGKmg#s1REP0z^$~Kd=`yV zJv=-nf!~xS2iu`mW!*8xH*)4F1RFV2RfQH*7RAAM@0{Uwur@i1BzcR^z@0n*$a;8q z2(Z-EDaWeXxgO-00IUIZmDkSHSoYO3A%tQ#NUwvWQt4#=ELTZ1wkt4?a9 z@nCJ=(O`pC!}wGQmqGcJZwp{=XGyi?T72}AB(zh#wFK^FF!aKmaDHQipsnV&(gumo zbs!g^HAoB~NB~J2Ep}&Ce-qYt#v^h^M|iA6AXxSx@WfrW%dTkk1Q(tPpMd#6ELn!g zz#(1qYY?`z=hA6X3AAYDHi#Il=Dm)ey8QHjkHlNiWqcwI$jZ- z)yjc$(&M~1v4y>`{pTC<9zmzcH=wE#ZJzkAb3Pb)i_|YQOXZx>1&7g) z1SPJX(7=v79&WC>TJW{yvBv-YtpQLkWl)ZT*g`)jef0>7kj~A}4(O4Zj|L>3M)FYp z$t%i*k*t&!MWFB03X-1_dkf^fIBP7>;Rl#yEKoM3r9Ct_T+0hJ#)@ioTSNsWT>}tZ zDL`wywkO{L{P|C|!k_u3z=GX=+ut%O1trfi(dpzco}Y4|d`AfeUM{$&GL332ALAJS z^kBO!XXeNqd~vwaa608E7I^x(Q=F5NbH;nZ%xUVQI{%MbYg6myN!APoF)z2Z)U|u*F6lbL6fZ*M%1daR<|f zP){0a$>;eHC!=`YEk=KfUXZKGW9U;fyuvg9BozXoyW4gb0vZ?S=CXwxDZne10C^CS z8AO!n#Yf|LJ5~@VXkIr{>d`u=FVY;Y!5TU=0_YK>v?4AxfNiO9`jY~9hamuIA_aJ| zwZgiUrkR{NC47L&DACG$3M_mgeyrvsRKNvS?Y}~Uid5vnXxl7+ekk=}WqkxdZ$^O1 zx3c+Aje^%49}W&tq&m>R)Ey&P@(>%8$j?D176@-cZK0t^xTEIfC=!Hz2^;xwl6f0)mUS0*3fi^uojY?a*&t?BHg0k`jDJ=I+u%=2;P;aoplJQ(^oQR(=s>CE zb~QxBOa(2hA1>pwm!?!3v|6~DTK+n`Lhlp=sPlzLqW1!JgaR*q=L0ck7>$NFVD7-S zaPJqI82Y5c4nWqT39B~Q*(UB#SLZL9E8mFpGQaqekk?EN3S`9KKGRx=47`rQA+0|d zH+cyd0D$v|7?^pJ0}k?gt1Evdm4weDK(?_+nx0iHlERpNwc0vh*0oir!8!Ydx1eU? z+uy0f91b=jxtEtc0eB@XGUvw%rcw-o0rG?%R$<%-exC;O58Meodko7z@@3!3hH`hs z2u>p~7!)x+6XFw80t%{rtFj5igK&j1%!MvW3!4t~>6$PgKpqirdjfwP*Uz;7fEObl zaGU^qZol+YQ;R#1MDid&j#mvL0l>#&dOvPSv0$A*&y^I!NX<*%GiAi#Qn0P@EsWMz~ecF z-?YwCH3eWjbw3*pgT;OD;1#kz3+N}28bAte;~yXmJCQuTfjO=})ottPxF8vmH%*4W zr+5XN)a~}#A4x@k91q!LhD7c2BM?N==V2fV+!XWfVYVdUf+Nh;sbRdoLttJW_$d5x zb-gxApg-#xu#A6K{?G^_DZys{qt7y>A3vTu(Xi;YNvbcri?F-7_NoOCaLh&%fQH~8 z8oa!@7}b(l0Vz?jhizN`erh=GKw$n?fE`v%9kffbV-LTPR3qLG$xkX_Is2tcns7M9u zSBEjK?j(9VS->3tW-AB~_&~Gy8epD@+fHVC4F*N6#42P5x4H<%*;G;Cv`bSEbU1aC zZ82IeR%y!&s-6O2B?|0Waa^tKDpC+`P-Px{DG0b#zQ9u_sfcnrXhl8|ib!Er*3M0o zn)eN5+Ar)U5A{ET+zk!M?XBeoCIREGH(X`GvWM(oOzlQ7m4V^p0SpLQ92^{tJn0XA zzS)6ILDiki==x#Q3m~exKzR)|*3tI2!9(DbZ&Op3cbHZ3D^s(zgUwvVnnMN3gvtrZ zUR3PxF8hMK7^#Z|aXSG7;9S65xr49=0S;4fWau*A`T+!E0S5$!1^Eho-ERfkqrq2Y zI;DhwKKp)4M?s-17k-&W4{~pS5s$Pq&AVcW6pUEz{>Bm_7-Rb}iq$@&Khtnja0v@M zGt`Z9`tRe06~PD{8er_)9@=vH zTy?Yt=plqOanCo<`0WPhvV?SqGKE~{W~LCi;B0LPI5|Ha)uMh}2s8Z2olbbi3gvt~ ztu3_Wr@J%sERZMCAw}e4=x;y(zZZ6<0fyyxXKW5AtZWh2)w^4*X$ul0c$+2S`ZOAs zyqP;w_MUs1N~3^N=T3N-zx4 zcgO~g49(2y6LNn@k2FijH_LX^Iv2g0!cL%bzB!q|!NXey^ur=@tAjiObUx+*>A)yB zt$lW9RFfH`sQ4@)U=?1#!%%+o^a$7wF}cPKV~$}75~byS0@=zB$ObI^Zz61}cHTsm zlE-v?=-vrPB2(VKx7X}KLsI<{=7EWybevnz2l8YF!OrLhY?oOs$E?!n+3L>ZK0_WC82k>NN+}FF@Qfxk`BJK1YuCbg)a4h*w$+K!=1IV z7zZPNh7)4NU_@$3`WBw9b^J}n=M@IV$j$w#tEg?>=6zI9eW2$9zqwwMxmz4Fuqd`@ z3qf`e0NU!C+oHTnkFG88b}`f7C?$300Q6QdndSmkL&$c-A~fWE6>{$Pe@-T1~`TAZlcq$0L2WlpEu;% zud?knpmYng1&knVx-(TgVYP=kRWuSl7FG%ca?I7xHB^~GkAbOy-4OQ$I7)8ltv@*J zWI?q=KL-dBdcfz{%r*NzjXXrMnLP}F8dZh5%Ehe?kVL5eRUNF9n_CNJ8Xb^ze*r+{ z(SW)6>VNbC!lerXONIvM{P*TJa^`Zi`?YdXdY2-bdwXgKZ*Oich$ipzz&wZPI&Q!k z3FSZgNJ2vLJ6j~Vx|$CZw~FBW1&n*p`l{&wdkwfW+?FuioW)m9i zCgk;Sn~Ex{=3rN&mPdgig{W1$;bSn%-|PZPL{xn6EaxvZUgIF`A)pn01Ilk8mv(JF zz_bXtD4vUPiM*WAhEW{ttWKmt6+HeH4z$zhhPD*LJb|(+4o-!rJ^gag;vgzrK~2@3 z)@#Fsu;2h^KT_Hcf+*NVitU^!c$wIRz14*?l-azKxQ*yU`w*lIc zEU>P>X$(Qa+50l@J&+6xfz-&A&~`rjFW%8}UYcntKBYuk@>s@a6rceI&_gM_t>+Pd zQceNR&$2UOF0!mQryNd%^B50S{?_mt}^Q^2P>A}!- zvvnu*uJnL%hYV1Svy|NgPPYb2RG3U(TKjAwVnJbwi!lDB_`kIPxVX(YmD^RtH?Y#Q z?ck(}0ecBX5XCEKlo>RK4j4kQ;pTh;)gGq9UPfxnEGXGh$K zO+_8WB!nmsY*`%;*0qg_t#+|Qcg)H@Dnu{s32CJuDapC4zwycmu?=q2jQDK@Yaxk;$rMn z;xHR@sf1h~0BM2;5DMA>RBC+u6=20O7(>p(ffYd4&7aobrqbZEO8HtvA&#XR8aTUB zvjOJV;qyt$B$?}dG?2oxa&sqwB|ZQOv?HMFLfZ$={|XvAkWCxFhEzfh?-XP=!$qJK z?Uh_u*I~|1j|@zcX|gplZrOpeI6<9e>n=>E zp&i%M8h03WAu64gnb`{x!IwZH0c0Nzy|nc&?(d!jYNCucerdIptQ~*#-LyYbAO(1?px@-5yh-7PXnK-C=|uXb{Qb_^qU7b-C%_If z1gta1z`uotrbW|A`tboG8re>REPeX3MFJ%zja78tnd`dTJi(bB*8l1f$?_#{cE!o2u^D$&FraHt_^+%g(4pukF;+nWu?NGfA6xGW1aMflcT+=nrsV| z0g?YNDCZXdB@4doA^|k4qymiW2pnRMUyj^={`@(pmp*l-HZs(QIXCANJ`3(z86GGY zvC(Pfj1p<|*--;uv5*&Zi1YaIW2DqaXYFP55Dx?BMm*a7e$XHurdL=7XjtM}E1)5Ca%0Q< zCs3wZL+cN^Y2)d*C8VWu!8c^c4R#i9HV9a7RYrs6t=xw`CRYb9B+0xcNMK>dAhx() zns1F)&_9bb=O_8N_R|~`up2WC-$u_W8&+v58%ki9<{4&O{%LS>YUHcaC3k@lTcEw9nPeF`t%8q)<#(L+_6t1uQzr>3!Ro&ChkN(c6C7`zND8=^0i+cIh-cz{ZKzk^S5^Um zcp8&oIn+0A-oABbW@YUhi?4DC2?;UO*B>XLV|V8saOJ67BbpBT0Q8Txrq>-jSf=iv zU_yX)**xC^Dxt9V0Nb~Q^+uVwlbtF5I4$mkm(0w}a5XgW^m8)cnP%qY!STCDK7qi$-tw~z zy-@`&?;BwGtO%uoR@jKPj#<5f&?Zr18ZRz+*sXkGqep?Tj^ zX{Vd*=SudQ=?gZ35o_Ld$4ghgr-Qar?_JChz_s8Ml28q_ z5S0!Eq>*RM{rdp_7mu$_;GCH~Yp=cbx?*-(POzfd^hB=Kd`g`)zQ3XV;a#YN%8v@o$GEw`N);~qLx;LbFc{-_G(K31vH!xc~)}#>BJ^tm2mLX2aq}YVG&&=Q! zUsdLf`|j>s8__Gpyt9L|Cmt1USYGaC<&}h zn4f!~lsOb@wo-Bv%|3f?YH-U*IW4Eo=PK9z`-GW=*l~?)k^u2zlK##%j9%B2kgfcK%D5YTo%G3%ybCTpDF* znsk9O>$53KBcNppH03ivi{R}* z=lvUa%vIR#t>ya`bE%)pCw3(g;&eF*#BbORi6>#%8G5Icrp!$48uHlX=Gnca4EyD< zlq^C;%9V+^a@Z|#+9P-4(N5FB%Y_puvf*}dy!pe1sp)o~sfI5N+h+H-=A~B7E{2J9 z6O_3^(d5x=*(s@u7-w?xk-?1=mo5JqzmGZ0$^5q3pu)1FEXPaHJ*ECCQb?07gjm~B zW?q@z%$Y&7UefWo1De(M58-x>{tq|X{Gh#yDO$FE&(%RulvD(M7#Ur5kNra80!sZF=)va+8xCRjX8wQ zJA`y;tv<1l6v1?LXn#8MaJ_P`(Mi!89f?*dC>+-`jS607i7JlQl(gz?&>nG7pd*>G z%SUCqn3+ZdOR&z^He*yDu<3+E)0+2dzF?kN^~G{1_L#9Z59Du%5oiB!Xu4ZIuK6s@ zbMvM4G;Uzc$SrwWn@Wc}ifNuRVq1Kp#az*ux!4!XE8KD2k`bv^hLBhUqVJ6W3L$4R>bXiT20}`iJ)y*>^wE zL>F$1o-+)NWhT7%3dZk!iK}Nx zN0q{ftDoS6l3$64Y+jpy%k{)^H0*uU5gaWH*Bab2PJLCuFjT)m?NrFV=2e7Td92)f zJ?b>ak)zPY%amkt^!<{!vnJb>vt#BBbz#mFk-rn#JllIDwPPMKbT(4rkSJA-a)oRy z=W>0xogFDH)OH}(QMZpKsJ7b0&W@~3Ha9A?{-<@>p*&@= z`O48~j<0WeSt7Iu>=Qa_<3#k!X%C0=97DEjQnAzDg;;#b&)vLsh}UVYrFQ(;?t&(M zbM~zVI;7M&?!1v4C&fgcHD-;iIC4+gt79kAvK)@o+qyX-_vVHp4Io9Fuudx;w(JZJuv6-+tdwY~3I`6`rA)fFo1C|lKfNPbt&@8X3iMw*N*y&wMRT(Y|~zP{_6{uErI+qI)df_u2$|4 zSNw0n2P)4=+{f*$M+gqJc|VQ6e z<5)7gGo+MP1vxAP+f0eoohV}rJ+bKOre*KKzMWQB&vClP@eH@KqJo6BMdJK62OP8U z^@x;dT#G>3zqfaHZMdJ1b@!7WUsOAFM3z;QzgXiJhUkPxESZUz%?; zpD~!ivGPv#@StXf$F-9I?ip{GYLmrS1j{~n=kpT zKjM?$VSX)r`bd*PQ)Gn7-BzX|EK_=8|FG^_fKP0iBkIG?eHu16BTVw3B<=r(kRW!B z@_!@9*Xw^(;@mT4^A@L6=*UU2Wy_A(IcY4s#YPqMG^u!>F8{CavR~CK#ezRiAGtiJs^7?-)SnRB|73a9h&1=oiw*^zG^ zE}n8_?=9K{?QGt|8C8-oTJ#McKfFwJiqS%v+rwZ_h7wgTykGx336Z3 z83tZh=MFwTWj-hwh&MPk@1w>!RyjyxkP3`P6O`ui{mwAT&g3^ZH1Ffrj!7iTQ_0_v zraBrT%_-k*v(yWWVW=$5sLWW4J2#?Xw!|xhgvH5K%_`eNYFPapjniD59ChtVp)OB& z>c82CKQH9)6>W{3V*|Dx?NuxOW5R}S^mD5}g-miMk}J^pIm4-&TM0hWvzL^79_72T z&fWX3_^zYPRsLD>N3j9CIc<<# zBhBSGEupYXr8(WHspua4$g%#X>DL0=lFjTeGI@*+r3J(8bt#Jlslu4LP+iZ_3KISN zmTs0Al`iCekV4V5t;xV-RMalGS-Do6mcuMLs9pYq(lTGed5acj+HTyaaD{xH$gzP_ z(!q!K$=;vM-^7rl^`l4n=AKJQer2CUx!qzKCe1BVuExj|v(R-^3&C+#SZPOp+cIJq zyZmJIqU`z$YN3&K{f?hKPOG4+3q6W++NjjUicLo=B@}UGx9iI>E9R$bpc(qj6xF#V zLpZZ_3m=T%L7&*#1op2Qeb*y*jTL|T^=lY4K_qHuy)0fkeqMA}KEYH4mo&RHa+gKo ztDS_yrfiYaRutOwuSLgSGK)^mR)N(gY|b56cZUBmg@DE*yJb(1KwG+PmDw|Jk28Nx zc9Z?kiuB?F-=f4pGLvU%W-^3gigu2GwmLJQv%pkC6^&|QWDWH-%}>Wf?@5?Ifla>h zLy1`>pP#L{h5@~zg2$|%&re>pP~maz%luMu%XCL2t4EZPkx`7^=R}V%R6h2Z_F)g+ zGH0fo=f5^A7s~6#$@%GH4`zOX(ig#dK^k_2EIKus5SaN%M@L@4AtBu0f)lm%K0n`m zb%f<^()GxUjAr7wJdJlCYtB@?>^I2{T3hI|+I%pq;+dZpCzAlYd+5)PZf;PhKv!oh zcMUwIj*gC2?Vkh!8tHa=;0RVzDnXbyZVoHZ)0O*c^ZI3t{_gr#KQXX_wQhN8uV@akG|uD zQF4Elxi}uCpT$7B*8s=XmtG)pA;ioUL^9fW>O*)FnTOiRR-U))0j#+T67tKGlnP*#DT;=8W z2V2FSZPSBBkxfj@ASunH!PE6u-xVNayl!a;fU(cbbp`EE-y43l*OyMh)|{cSJ~1(| zXDQOYf*}UC2x&K6$50w=_VWdlp%ZvRYqL{~zMq$eGnmN8$eiXUB=0&BL(6{|Or#zo zOh#~!)$hm1wCs%o7cUn8mcKFFWHSKz84&eyp=DiUTsLMfjskWZ(!eeUl%Mvdy=4_W z^owDrbD^cS2^OsI7obOc>)d?&5+R%b3Q_nAwfO5-XlbbcAg9%agka_6w$X?H-^z^M z9rB8Z&lpgcumkh+p~LMXJkV7JV874)s@#9N!VX5=TEueJCd01_9KBY*6u+BvL$Eh! z{vo`st=TQ1&QKSFQmnD6-WNQzGm?q=!9ilToG64bg@8q;heg0ST>J zcVy?_sIVTS9ZHi_26+$|_olO-2*=07v;t=fpN#C*U^jHtAC_C-0PqJIBV4DIJs96( zP#~)UbOM-lW8pvtuuQ=Z>y3`#BWUr$_$(AF8G_6c2Ax%0JOxBjI?xUs_pr1E%^tms ze=7L3mKfK`Ly!WPZS?nmcx5E(&U0WEA$b70|7#z4^O9f^K@cgzaS)scEPJ0$Vyb~U z8(>-EMlWsq20swR&((W`&(=7{gS#>On(^OOMBfi+QBRTp6P$R`j3@Z~{Q!pBcewmq zC6ZHz_GI{57#8qAJ3f^WO$Izbzr?r~JOR9*Z~Xy`muGFlsra++WyynzYU3kGvhGl- zcss}-`+?c$_3wD)+x|mEpnQQ;v#HR30Y+{boYBB(HybE9dDRc1luC4TbdG?j?7dmu z4Q6mbvo_$y2MnOmhG)*e&Fupi;W2t7wIblcAEBYy+Hy^mn$;+Tw0}ngUx9(BlfN7P zc`3uF=EcjGW1yb(IoRw4gJ29qcuFH;9kJ0+XjF5(x7Xsq8^~(F{!({w5d@6C#O?$I zu3K`TYzJO~dtqLq(>DpojmqGd2#s2xEhi;VvU#5NFaj%TIE42aJRRXCTco5z3U@z0@tF7eLDGD-s|FE>iw-OVgd#z}EFCxn;QZ_b z>e9#c=@1uiDu`b(%(WjtQYf)V0O$mPUf>FKvK0sb$x&5N5j45n3Z`KxG6B+%qpSdt ztFFbfL#(>NJ>0l{0YV3Q_NwOQ%n0}eV+wZ;bBS>x>kb}dDFR~R_dv@UdlIoVR~O&x zcZv{efnluy`5cB;=cXmxt55_d1ituh07Gm2M1fdR?JzA5j7KpLkCD*cSUhlSlAQVW zj^3lB#I)%y+(U@aYi7;QOAdkC4uU&Em=yU2inC_u~=q$O2J=Ig3 zY6o7<>#(qFn1@FvC(y(n0)qy#0$OmKghh-LPC3uz`{$=S^JzdXbpO#sf{3RfG9g5T z5t9a(^&qb__}E;O432xGui7VKhhbrY*`@^2TmpRjMS$dOfbWe0TaYw>JhdUoBT&Xi zdD10TSSzIjn)c&nZ<^!Ya-O&RTK34x%d7Sn*ajJ^3oR{b3xE#ub3aW{pi)(AWKs4skFQR64DuZbRMaT%)W&o>*6#Z@k@{~6S^WU%c55QD`@XiDR zQl37U^VoX=!~k*Q@12Ja)mQ@j-i0Cnp z$?`HDMAF?_1`PIDlMH~ANzJir%DX`QUY*fr%ZDYr9E1pvpb(~#hog}NHsam@z9zT| z%*k)x@|^pOLp`;aVw0Ywl_5O^*+Js-{HYj6emiP;?mEfk?+0o&0u=z0EYl#2_RT7jfEZp1#@aN;_ z3*k_+AQVD?;<}axl{Qt=Z~LEa-9ljAsSTKch;Rbce6&Qg{-t>1gb!9Oz`o_|wWn+5 zeTc~AIsm}7o&0#kV|^laSw;lPC~R!(djOs`c-}{#@!35An3Z{&If7R5r;q~efZ+;D z2wT9vGwa$O4_h;PkbT3nvViM*W2d5~hL9r>Yo6lABap9=k^nf>DjFJzC0cAZZzckN zMhNI`<9^;SU6#M6LHUJX@i55s(lVeOhBROaB>*-K&a}mo=m>BVK#14C^2H}6PAJ)# zsd{pBd`xlWO6Pmkc*Ji7aM1XVEFw_1bdKxJ%|Lck0)UsFLE{ugxX$lX6nMcLtgN3W zgMJ?zAPcC&Y<1+w$URWPb6E||L6$)lVp!oGfzky?oe7XcQO}=0H+HOfe(VNx(hmkF(CKrRygcG!emFZkAji~o=?31k(7R}9$?!y>`p9WCM&QscLG zc787Iz5D)Y0!UsX3xJqz;0n>A{X(ZE<|18>7= zXBZgjV9km~9=-r`t6qs^&=QP5O0uS*z7Yam4~NFv4j}bh_i$T=TnRZ#=HhhWVouby z1RfGVC+e^WX$w}rrLC<&I_E|fjj07~(Ef-zd~Jm!florh4q-t|Ehzgoz|71HmgRLH zlTy>$h`|8lm-lwHR}n`|kp9M0*UZ7{lPvC@xA7Mg=*Ue|d&8Fn83s%~VxWq20Zust z4OVLejR>`n1vXI05oZFhjQ!?evi=Cxwvrnf1vGI|Fwh%mTFxem;cateGYf1n0w`9<@G8lpldHR9LJGPBnU`!y199VPXAGFyJX*XlQ znX9aWTSnbrk*xrvDg9DY4X`_b)rlF(E+7%UTNeS`7@m00>Cp&EB)`QQyK{B!VEIkff%84O8YfygkW!Mn> z{`PF495OxJBOb>Rb=V9cl)4R%V#6vimqir9&I5udtX^eMt3bdb!weMppTLkU*)OT7 zxdj^z(Moryig>43Uq!?=yo7B5SU-5s{rTGD`yWea?7iyPa)I=251SKFROLeP9QHp5 zErj=qLqtV>^{O%qD-?{6fY>#rlQ=&=5Bdov^5Ga**AVYz*-8xyi|h^OQnMDPHI8}6 z@W7OR35)T6S>iYFkn5C;nf9fSrzPZTWmuo=uUYqDJ@qURCe^l9gkz_tr{Dj0Up4w2 zo_v3mb!grnf5SoR-JiWsJoHSK`+#*)ZYlNIQn&z&ZAsK5@NZUUsy0kwr=e_p&!101 zO4_{96ycu9p_M)W1&um`-zpfqz=IlGJ&Hi7_Kh))HsIfJzEKJ;`AR~>9?uW)=cVGN z$Va(s*~~iFAoHrak2te{J<=nn9=yE0|A2uD1rw7Nq(=3>MirK-ci-@>9n3?V7C=JT zko4W{GHfK12%43M>C&MC&*kLSbfR6*&CFUaw%rU55U7(Es9|L=y6$UR0B#sVqwXyK17v!k0Ip~Hp=NPmJ zu)K#sX@it!^76rU3$yV1$MArbuR#2Zjg3VzHx(X8#=L_lr6~Gd$T=v37XRA_F%wL}ZfGd$1D%B8(xuOk6%h^- zG#lLCFzBWpL80F-! zL_u@`bNck;2o|)RfPxITh};i0hI<4Z)w79fD!B3B;{LYebAJe-Y%r7cc82}mypsdW>&J3tfbyUBSS)(rS@xa|SI zp+Nz=Xgx5);M1E`X7cL*lQIls*D4|L7B-)1lQAg~e(@3UGi+ew1sgpWKEyN_){qp5 zZXsp12QWwog}TyCS9bpc?0+?3TS6n_F9ni4Hpu#oyM4Ui%1u*nYZmeE0b@Nd=lBe@ z7q{L=N-gQ*_xDL4g@fz)7Y}Vpp8IHE=jwfYiMV``F>c;1^!D`~FEx`vLG!2wDs{w5 z2S`5y4W3i%x#Hk2@=Y5opWU{;iz@}(SVr`4UtdafrZei%Pl$~PMh`<>!C+s z4f~P^CYf~Pdsx``#)m7ANP|3FLOlA4$-f5}U{IUD-feDD8nWZlwXx2LRu<(nUNW+1 zUn&QX4T;?c@5v6VT+df z3>nRD_#*M9{5a%DzJ&k?KpH8pGD?!e&;9-3;A~_7h1lWgP*En77;tvd{liGjS)FQ% z3k5E03`F{eEwBF=j>yl?=ij-5Y@c%f?RcDr)GBKv3(95FK7+O-zhC8tu-l-!=tv1BA=u<L!%GrYCU>Tk5$SVOe5(^K~1z-VTk^(>-E3${$JM%8I}Lf50@?^af+y7aOU-i zdN3s&9{oyOtIB8Rfdi-AJ9NSFqD&@hBx-ajr;5DPdd<9cQa)7*Lml-Jb0HQ?*)%c* z1sPV!ituKPc)KIVS}6(@#g6fhNRF_wdapCQQfd_}TIiU%T)wtJut@Df<<+gDXyN`N z0LvLG19efMPm0nD5^q%j!^S&QYh0KSsQKZ2e@=7Z-%OcrEH$)H+OmV{J5$Zwr`GXI zUL*!_Yv=fj{N^0LS=_MRbq8t%t%x)}!25HX6sMZyFlFhrm`!t2_lhIMRJ!_E5RL4D z`VJE|DQYFCAnxXxHP#a5s6SbyCLwe4kzDJoR_gF7+s(xx4GXF-0liJN;}rj{X1Ckm zNd=LSH%!k4DZ+3BCs8wo*Z5~e znM`H$qod>ar~|QpL%eFW30)d$)HP;_%#?+efi%x}#Rm#__I@u98F3E80}f>!bW9$^ zrH{4BE((tDw4W|uSf#ZHV423g$6FLPmm*K zW(#Zct%l6BsnDRC`h>1Jj6!1ubZBe|Bi>ifWdRD3jgX$>T}oICRkz+)>O56Im3|UewbVuO=~tUC34LDA3*voc_|s!r&@& zU3sqYx)CoPxdb8en2YCk!r!df@i#aA1@MG^NAJ(lwI<2>J^6)NYQ$X)R{3Et$enqM zoa6}O;*&mUP0%>{{&jS0boQ6ty6}O+-{A%ser0q8=qN^XZ1ELz>@{9hJVPvAinbRF zBNFQcFvFH2YrjaqJt^M4Sm~1ZqK2`k|8j~k#gun@F}x?XB@j(oyi6?L|D$ynjh2~b zFgJU8U|DNg?;PE z;Cv?F|3kCPA6tlFg^ngF(hJSd=I6G2r_~i}bNObaYIQqBe872e;*T!IMGn@!nlO2E zY*z}}lLvnQC(P&rH`^2i!_p=?Bp1OQki%oC?T@G z>!}J$@|W10`fSMCa}rZanYtMZFv!Uq8U{2{&<1{Pw4<-rY>Md_ziXa|QrC8TJ9bZ* zlT}yP3_<^PW?g=1a9nnMC@s<2ih|nlk%=*<#;^nU!RoMrh5H zBW0F#qJU^owFCc6qK_x@_JSYzaD7Ig9hGh0(E!=6A>+Dw71}D{xVz~2b%Tye>XN@{ zm-^>}Z}$|=(DnaLL% zp<|g#bt?%1OH%XU$=&yb+D}D3d70r3QWVZV!?=^WbBYS!?INp8DmlCneoO(_Kf zcc38>^0(pRd`|zMvkwNS9n2 Date: Tue, 16 Apr 2024 16:42:39 +0800 Subject: [PATCH 6/6] docs: improve wording --- src/main/java/dataStructures/segmentTree/SegmentTree.java | 4 ++-- .../segmentTree/arrayRepresentation/SegmentTree.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/dataStructures/segmentTree/SegmentTree.java b/src/main/java/dataStructures/segmentTree/SegmentTree.java index 77e9955c..f860d093 100644 --- a/src/main/java/dataStructures/segmentTree/SegmentTree.java +++ b/src/main/java/dataStructures/segmentTree/SegmentTree.java @@ -66,7 +66,7 @@ public int query(int leftEnd, int rightEnd) { private int query(SegmentTreeNode node, int leftEnd, int rightEnd) { // this is the case when: // start end - // range query: ^ ^ --> so simply capture the sum at this node! + // range query: ^ ^ --> so simply capture the sum at this node! if (leftEnd <= node.start && node.end <= rightEnd) { return node.sum; } @@ -101,7 +101,7 @@ public void update(int idx, int val) { private void update(SegmentTreeNode node, int idx, int val) { if (node.start == node.end && node.start == idx) { - node.sum = val; // previously, node held a single value; now updated + node.sum = val; // node is holding a single value; now updated return; } int mid = node.start + (node.end - node.start) / 2; diff --git a/src/main/java/dataStructures/segmentTree/arrayRepresentation/SegmentTree.java b/src/main/java/dataStructures/segmentTree/arrayRepresentation/SegmentTree.java index 0ce95d23..a75f656a 100644 --- a/src/main/java/dataStructures/segmentTree/arrayRepresentation/SegmentTree.java +++ b/src/main/java/dataStructures/segmentTree/arrayRepresentation/SegmentTree.java @@ -54,7 +54,7 @@ public int query(int leftEnd, int rightEnd) { private int query(int nodeIdx, int startRange, int endRange, int leftEnd, int rightEnd) { // this is the case when: // start end - // range query: ^ ^ --> so simply capture the sum at this node! + // range query: ^ ^ --> so simply capture the sum at this node! if (leftEnd <= startRange && endRange <= rightEnd) { return tree[nodeIdx]; }