Line Segment Tree: An Efficient Interval Query Data Structure

A line segment tree is a data structure used to solve interval query problems. It divides an interval into multiple smaller intervals, and maintains some preprocessing information for each sub-interval, which can help us quickly answer various types of interval query questions.

In general, segment trees can be used to solve the following problems:

  1. Interval maximum value query
  2. Intervals and queries
  3. Interval Maximum Consecutive Subsections and Queries
  4. Range coverage operations and queries, etc.

The core idea of ​​the line segment tree is to recursively divide the interval into smaller sub-intervals, and merge the information of each sub-interval into the parent interval. When implementing a line segment tree, we usually use an array to store the nodes of the tree. For each node, we will record the interval it represents and the information corresponding to the interval.

Below is an example of a simple segment tree, which is used to solve interval and query problems.

Suppose we have an array a of length n, we need to support the following two operations:

  1. Update the value of a[i] to v
  2. Query the interval sum of a[l...r]

For this problem, we can use the following segment tree implementation:

class SegmentTree:
    def __init__(self, arr):
        self.tree = [0] * 4 * len(arr)
        self.build(1, 0, len(arr) - 1, arr)

    def build(self, node, start, end, arr):
        if start == end:
            self.tree[node] = arr[start]
        else:
            mid = (start + end) // 2
            self.build(node * 2, start, mid, arr)
            self.build(node * 2 + 1, mid + 1, end, arr)
            self.tree[node] = self.tree[node * 2] + self.tree[node * 2 + 1]

    def update(self, node, start, end, idx, val):
        if start == end:
            self.tree[node] = val
        else:
            mid = (start + end) // 2
            if idx <= mid:
                self.update(node * 2, start, mid, idx, val)
            else:
                self.update(node * 2 + 1, mid + 1, end, idx, val)
            self.tree[node] = self.tree[node * 2] + self.tree[node * 2 + 1]

    def query(self, node, start, end, l, r):
        if r < start or end < l:
            return 0
        if l <= start and end <= r:
            return self.tree[node]
        mid = (start + end) // 2
        p1 = self.query(node * 2, start, mid, l, r)
        p2 = self.query(node * 2 + 1, mid + 1, end, l, r)
        return p1 + p2

In this implementation, we use an array to store the nodes of the tree, where tree[i] represents the sum of the intervals represented by the subtree rooted at i. At the time of initialization, we recursively build the entire line segment tree, and then we can use the update method to update the value at the specified position, and use the query method to query the sum of the specified interval.

In the update method, we first judge whether the interval represented by the current node is the position we need to update, if so, we directly update the value of the position to the specified value. Otherwise, we recursively push the operation down to the children until we find the location we need to update. Finally, we maintain the sum of the interval in each node, just add the sum of the child nodes.

In the query method, we first judge whether the interval represented by the current node has no intersection with the query interval, and if so, return 0. If the interval represented by the current node completely contains the query interval, we directly return the value stored by the node. Otherwise, we recursively query the left and right subintervals of the interval, and add their sums to return.

Here are some sample codes that can help us better understand how to use segment trees:

# 示例代码
a = [1, 3, 5, 7, 9]
st = SegmentTree(a)

# 输出区间[1,3]的和
print(st.query(1, 0, len(a) - 1, 1, 3)) # 15

# 将a[2]的值更新为6
st.update(1, 0, len(a) - 1, 2, 6)

# 再次输出区间[1,3]的和
print(st.query(1, 0, len(a) - 1, 1, 3)) # 16

In this example, we first construct an array a of length 5 and the corresponding segment tree st. Then, we calculated the sum of the interval [1,3] using the query method, and the result was 15. Next, we update the value of a[2] to 6, and use the query method to calculate the sum of the interval [1,3] again, and the result is 16.

Line segment tree is a powerful data structure, which can help us efficiently solve various types of interval query problems. Although the implementation of line segment tree is more complicated, once we understand its core idea, we can easily apply it to solve various practical problems.

Guess you like

Origin blog.csdn.net/qq_29669259/article/details/130258564