數據結構——段樹

2024年2月6日 18点热度 0人点赞

數據結構教程:段樹(Segment Tree)

段樹是一種基於完全二叉樹的數據結構,專為解決數組區間查詢和修改問題而設計。它能將一個數組的所有連續子區間的信息高效地存儲在樹中,使得對任意區間的查詢或更新操作可以在O(log n)的時間復雜度內完成。

基本概念與結構

• 段樹的每個節點關聯著原數組的一個連續子區間。

• 根節點代表整個數組,其左右子節點分別表示左半部分和右半部分。

• 通過遞歸劃分數組區間直到長度為1,形成葉子節點,對應原數組單個元素。

基本操作

1. 構建段樹:

• 輸入給定數組arr和大小n,創建大小為4*n的數組模擬完全二叉樹,並自底向上計算每個節點對應的區間和或其他信息。

2. 查詢操作:

• 給定一個查詢區間[l, r],從根節點開始自頂向下查找,合並沿途節點信息以獲取該區間的結果。

3. 更新操作:

• 當需要修改原數組某個位置值時,找到對應影響范圍的段樹節點進行更新,並回溯到根節點同步所有相關節點信息。

C 示例代碼片段(區間求和為例)

class SegmentTree {
private:
	vector<int> tree; // 存儲段樹的數組
public:
	// 構造函數,輸入為原數組arr和大小n
	SegmentTree(vector<int>& arr, int n) {
		tree.resize(4 * n);
		build(arr, 0, 0, n - 1);
	}
	// 從下至上構建段樹
	void build(vector<int>& arr, int node, int start, int end) {
		if (start == end) {
			tree[node] = arr[start];
			return;
		}
		int mid = start   (end - start) / 2;
		build(arr, 2 * node   1, start, mid); // 左子樹
		build(arr, 2 * node   2, mid   1, end); // 右子樹
		tree[node] = tree[2 * node   1]   tree[2 * node   2]; // 合並區間和
	}
	// 查詢區間[l, r]的和
	int query(int l, int r) {
		return query(0, 0, n - 1, l, r);
	}
	// 自頂向下查詢區間[l, r]的和
	int query(int node, int start, int end, int l, int r) {
		// 空區間或不在查詢范圍內返回0
		if (l > end || r < start)
			return 0;
		// 區間完全包含在查詢范圍內,直接返回節點值
		if (l <= start && end <= r)
			return tree[node];
		int mid = start   (end - start) / 2;
		// 分別查詢左右子區間和,然後相加
		return query(2 * node   1, start, mid, l, r)   query(2 * node   2, mid   1, end, l, r);
	}
	// 更新第pos位置的值為val(這裡僅展示框架)
	void update(int pos, int val) {
		update(0, 0, n - 1, pos, val);
	}
	// 自頂向下更新第pos位置的值為val
	void update(int node, int start, int end, int pos, int val) {
		// 更新到葉節點後,根據實際情況調整父節點信息
	}
};

總結來說,段樹通過構建一棵反映數組區間變化的完全二叉樹,極大地提高了涉及動態區間查詢、修改等問題的處理效率。盡管本例隻展示了區間求和的操作,但實際應用中,段樹還可以用於求區間最大/最小值、區間加法、區間翻轉等多種問題。