Segment Tree
Introduction
Segment Tree is an efficient tree data structure for dynamic range queries. This is why it is called a “Segment Tree.” The array is recursively divided into two segments until the segment size is 1. The concept of dividing into segments is similar to the binary search method.
Trade-off: It uses a lot of memory.
How to implement
Example: finding the maximum value of range
class SegmentTree:
def __init__(self, arr):
self.n = len(arr)
self.tree_size = 1
self.init_value = float("-inf")
while self.tree_size < self.n:
self.tree_size *= 2
# Create the data set
# Space complexity: O(2n)
self.data = [self.init_value] * (2 * self.tree_size)
# Build the segment tree
# Time complexity: O(n)
for i in range(self.n):
self.data[self.tree_size + i] = arr[i]
# Time complexity: O(n)
for i in range(self.tree_size - 1, 0, -1):
self.data[i] = max(self.data[i * 2], self.data[i * 2 + 1])
def update_node(self, index, value):
node = index - 1 + self.tree_size
self.data[node] = value
# Time complexity: O(log n)
while node > 1:
parent = node // 2
self.data[parent] = max(self.data[parent * 2], self.data[parent * 2 + 1])
node = parent
def range_max(self, left, right):
# Base case: left must be smaller than right
if left > right:
return float("-inf")
left += self.tree_size - 1
right += self.tree_size - 1
res = float("-inf")
# Time complexity: O(log n)
while left <= right:
if left % 2 == 1:
res = max(res, self.data[left])
left += 1
if right % 2 == 0:
res = max(res, self.data[right])
right -= 1
left //= 2
right //= 2
return res
# Example usage:
arr = [1, 2, 3, 4, 5, 6, 7]
seg_tree = SegmentTree(arr)
# Update values
seg_tree.update_node(1, 2)
seg_tree.update_node(2, 4)
seg_tree.update_node(3, 1)
seg_tree.update_node(4, 5)
seg_tree.update_node(5, 4)
seg_tree.update_node(6, 3)
seg_tree.update_node(7, 2)
# Querying segment tree
print(seg_tree.range_max(6, 2)) # Invalid range -> returns -inf
print(seg_tree.range_max(2, 2)) # Should return 4
print(seg_tree.range_max(3, 7)) # Should return 5
When should it be used?
- When we need efficient answers for range queries.
- When we need to update elements dynamically.
How can this be applied to real-world problems?
- Stock Market Analysis: Finding max/min prices in a time range.
- Big Data Queries: Efficient range-based calculations.
How does it compare with alternative approaches?
Segment Tree vs. Fenwick Tree:
- Fenwick Tree (BIT) is simpler but doesn’t support range updates efficiently.
- Segment Tree supports complex queries (max/min/sum/gcd, etc.).
Segment Tree vs. Sparse Table:
- Sparse Table is faster for queries (O(1) vs. O(log n)).
- But it only works for static data (no updates).
When should I not use this algorithm?
- High memory usage (O(2n)): Avoid if memory is limited.
- If updates are rare: Just use max() in Python (O(n)) instead of building a Segment Tree.