線段樹是處理區間問題的好的解決方法, 當有n個元素時對區間的操作可以在o(logn)時間內完成, 有q個詢問也不會超時, 根據節點維護的資料的不同, 線段樹可以提供不同的功能, 下面以rang minimum query(rmq, 即查詢區間內最小值)為例, 進行說明。對於陣列, 線段樹結構為
其維護區間與儲存下標標記出來如下圖:
區間用[a, b)表示, 表示a到b - 1 的區間內最小值,
圓圈內數字表示該資料儲存在陣列中的下標
觀察可知, 對某一節點k, 其左節點為 k*2+1, 右節點為k*2+2
可有此關係從某一節點到其左右節點,
同樣, 由左節點或右節點k可到其上一節點, (k-1)/ 2
更新a0的值時, 需要重新計算下圖四個節點的值
對於元素個數是不能組成完美二叉樹的, 可以擴大元素個數來解決,
例如五個元素的陣列, 簡單化為下圖, 這個實現在初始化下面**中的init()函式裡面
實現輸入n個數查詢區間最小值。
#include#include#include#include#include#include#include#include#include#include#include#includeusing namespace std;
typedef long long ll;
int n, n_;
const int maxn = 1 << 17;
int dat[2 * maxn - 1];
int inf = 1<< 29;
void init(int a) //初始化函式對於a個元素的陣列,
// 將元素擴大到n個, 整個樹的節點數為2 * n - 1
void update(int k, int a) //更新函式, 將第k個值更新為a
}int query(int a, int b, int k, int l, int r) //查詢[a, b)中最小值,
// k代表所查節點, l, r代表所查節點的左右邊界
//每次都從根節點開始查詢故外部呼叫時為query(a, b, 0, 0, n)
}int main()
cout << query(0, 5, 0, 0, n) << endl;
cout << query(0, 3, 0, 0, n) << endl;
cout << query(0, 2, 0, 0, n) << endl;
}
線段樹 詳解
acm刷題時遇到許多連續區間的動態查詢問題,例如求取某一區間上元素之和 求取某一區間上元素的最大值,此時如果使用一般的方法求解會使得時間超出要求。此時需要使用到線段樹,其主要用於高效解決連續區間的動態查詢問題。線段樹,類似區間樹,是乙個完全二叉樹,它在各個節點儲存一條線段 陣列中的一段子陣列 由於二...
線段樹詳解
有這樣一類問題 設有長度為n的數列 需要進行一些操作 比如求區間的最大值 求某個區間的和 或者在進行某些修改操作後再求區間的和 如果用普通的陣列儲存數列 然後進行暴力求解的話總複雜度是很大的 當數列很長 查詢的次數很多時 這種方法肯定是不可取的 對於這種問題,有一種神奇的資料結構,能在o mlog2...
線段樹詳解
一 定義 首先要明確線段樹的定義,線段樹是一顆樹,而且是完全二叉樹。同時線段樹的每個節點表示乙個區間,左子樹和右子樹分別表示這個區間的左半邊和右半邊。即將區間 l,r 分解成 l,mid 和 mid 1,r 假設根的高度為1,樹高為 n 1 下圖展示了區間 1,13 的分解過程 二 原理 上圖中每個...