线段树是一种数据结构,通常用于解决区间查询和更新的问题。它能够在对数时间内完成单点修改和区间查询操作,适用于大量数据的高效处理场景。在本文中,我们将通过几个具体的例子来展示如何利用线段树进行在线处理问题。
线段树是一种平衡二叉树,每个节点代表一个区间的集合信息。对于区间查询和更新操作,可以通过递归的方式在树中进行查找或修改,从而达到高效处理的目的。
线段树的构建通常基于数组形式的数据。以区间 [1, n]
来构造线段树,每个节点包含以下信息:
start
和 end
:表示该节点对应的区间的左右边界。value
:表示与该区间相关的信息(如和、最大值等)。[l, r]
,利用线段树快速获取该区间的相关信息。假设我们有一个长度为 n
的数组 A[]
,需要频繁地进行区间求和操作。例如,给定一个区间 [l, r]
,要求输出这个区间内所有元素的和。
A[]
为基础,构造线段树。class SegmentTree:
def __init__(self, arr):
self.arr = arr
n = len(arr)
self.tree = [0] * (4 * n) # 线段树节点数量为数组长度的四倍
self.build(1, 0, n - 1)
def build(self, node, start, end):
if start == end:
self.tree[node] = self.arr[start]
else:
mid = (start + end) // 2
self.build(2 * node, start, mid)
self.build(2 * node + 1, mid + 1, end)
self.tree[node] = self.tree[2 * node] + self.tree[2 * node + 1]
def update(self, node, start, end, idx, val):
if start == end:
self.arr[idx] += val
self.tree[node] += val
else:
mid = (start + end) // 2
if start <= idx <= mid:
self.update(2 * node, start, mid, idx, val)
else:
self.update(2 * node + 1, mid + 1, end, idx, val)
self.tree[node] = self.tree[2 * node] + self.tree[2 * node + 1]
def query(self, node, start, end, l, r):
if l > end or r < start:
return 0
elif l <= start and r >= end:
return self.tree[node]
else:
mid = (start + end) // 2
left_sum = self.query(2 * node, start, mid, l, r)
right_sum = self.query(2 * node + 1, mid + 1, end, l, r)
return left_sum + right_sum
# 示例使用
arr = [1, 3, 5, 7, 9]
st = SegmentTree(arr)
print(st.query(1, 0, len(arr) - 1, 1, 3)) # 输出: 21 (3+5+7)
类似地,可以考虑一个数组 A[]
上的区间最大值查询问题。给定一个区间 [l, r]
,要求输出该区间内所有元素的最大值。
class SegmentTreeMax:
def __init__(self, arr):
self.arr = arr
n = len(arr)
self.tree_max = [0] * (4 * n) # 线段树节点数量为数组长度的四倍
self.build(1, 0, n - 1)
def build(self, node, start, end):
if start == end:
self.tree_max[node] = self.arr[start]
else:
mid = (start + end) // 2
self.build(2 * node, start, mid)
self.build(2 * node + 1, mid + 1, end)
self.tree_max[node] = max(self.tree_max[2 * node], self.tree_max[2 * node + 1])
def update(self, node, start, end, idx, val):
if start == end:
self.arr[idx] += val
self.tree_max[node] += val
else:
mid = (start + end) // 2
if start <= idx <= mid:
self.update(2 * node, start, mid, idx, val)
else:
self.update(2 * node + 1, mid + 1, end, idx, val)
self.tree_max[node] = max(self.tree_max[2 * node], self.tree_max[2 * node + 1])
def query_max(self, node, start, end, l, r):
if l > end or r < start:
return float('-inf')
elif l <= start and r >= end:
return self.tree_max[node]
else:
mid = (start + end) // 2
left_max = self.query_max(2 * node, start, mid, l, r)
right_max = self.query_max(2 * node + 1, mid + 1, end, l, r)
return max(left_max, right_max)
# 示例使用
arr = [5, 4, 7, 9, 3]
stm = SegmentTreeMax(arr)
print(stm.query_max(1, 0, len(arr) - 1, 2, 4)) # 输出: 9
通过以上两个实例,我们可以看到线段树在解决区间查询和更新问题时的优势。其高效性和灵活性使其成为在线处理问题的强大工具。当然,在实际应用中还需要根据具体需求进行适当调整和优化,以满足不同的应用场景要求。