演算法學習14 線段樹

2021-09-22 02:15:47 字數 3123 閱讀 4361

線段樹要解決的問題是: 在乙個實時更新的動態陣列中查詢區間和(或廣義的區間狀態,如區間積,區間最大最小值).

若所查詢的陣列為靜態陣列,則此問題只需要使用陣列字首和即能解決.

線段樹是一種平衡二叉樹,其每個節點儲存陣列中一段區間和.其左子節點儲存區間左半部分和;其右子節點儲存區間右半部分和.

線段樹陣列的內容為[15, 3, 12, 1, 2, 7, 5, 0, 1, 0, 0, 3, 4],注意到陣列中對應完全二叉樹的下標9下標10的節點不存在.

為了便於下標計算,我們的實際線段樹陣列下標是從1開始的,0位被浪費了.

線段樹的遞迴構造: 若某節點儲存原陣列nums[leftindex] ~ nums[rightindex]區間陣列和,其左子節點儲存原陣列nums[leftindex] ~ nums[midindex]區間陣列和,其右子節點儲存原陣列nums[midindex+1] ~ nums[rightindex]區間陣列和.

線段樹開闢的陣列長度應為原陣列長度的四倍,證明如下:

若原陣列nums的長度為n,線段樹深度h應為⌈lo

g2n+

1⌉\lceil log_n+1\rceil

⌈log2​

n+1⌉

,則該完全二叉樹的陣列長度應為2h+

1⩽4n

2^\leqslant4n

2h+1⩽4

n.

private

int[

] segmenttree;

// 線段樹的結構

// 構造線段樹

private

void

buildsegmenttree

(int

nums)

// 構造線段樹上的segment[pos]節點,該節點儲存原nums陣列[leftindex,rightindex]部分的陣列和

private

intbuildsegmenttree

(int

nums,

int pos,

int leftindex,

int rightindex)

else

// 返回該節點對應的區間和

return segmenttree[pos]

;}

// 列印整顆線段樹

public

void

printsegmenttree()

// 先序遍歷列印線段樹第pos位為樹根的子樹,該節點儲存原nums陣列leftindex至rightindex部分的陣列和

private

void

printsegmenttree

(int pos,

int leftindex,

int rightindex,

int layer)

// 顯示樹根節點

system.out.

println

("["

+ leftindex +

" "+ rightindex +

"]: "

+ segmenttree[pos]);

// 若存在子樹,則遞迴列印左右子樹

if(leftindex < rightindex)

}

列印結果如下:

區間和的查詢應用二分思想,不斷將當前區間二分直到當前區間全部位於查詢區間內,這時將該節點所儲存的區間和其它所有位於查詢區間內的子區間和相加得到總的查詢區間和.

// 查詢原sum陣列qleftindex到qrightindex部分陣列和

public

intsumrange

(int qleft,

int qright)

// 在 `線段樹陣列中代表原sum陣列[leftindex,rightindex]區間內` 二分查詢 `原sum陣列[qleftindex,qrightindex]區間和`

private

intsumrange

(int pos,

int leftindex,

int rightindex,

int qleftindex,

int qrightindex)

else

if(qleftindex <= leftindex && qrightindex >= rightindex)

else

}

若更新了陣列某一位,則線段樹中包含該位的左右區間和也必然被更新.

從根節點(對應原nums陣列[0, nums.len-1]區間和)開始,不斷將其所有包含第i位的子區間加上對應的偏移量.

// 將原陣列nums第i位的值改為val

public

void

update

(int i,

int val)

// 將線段樹中 包含原陣列第i位的所有區間和 加上乙個 增量delta

private

void

update

(int pos,

int i,

int delta,

int leftinndex,

int rightindex)

}

演算法學習筆記 線段樹

在樹狀陣列那篇部落格中,留下了乙個坑 區間修改區間查詢 樹狀陣列部落格傳送門 今天我們就要來解決這個問題 都很簡單 線段樹是一種可以較快維護滿足區間可加性區間資訊 如 區間和,區間積,區間最大最小等 的資料結構,其基本思想就是二分。注 區間可加性指一些可以通過子區間資訊合併維護的資訊,如區間最大就可...

演算法學習筆記 樹狀陣列 線段樹

支援單點修改和區間查詢兩個操作,單次操作o logn tr x 陣列存的是原陣列在區間 x lowbit x x 上的和 若要將乙個數x變為v,則將x x v,即加上v x 模板如下 建立樹狀陣列 for int i 1 i n i scanf d a i for int i 1 i n i add...

演算法學習筆記 14 離散化操作

離散化是一種輔助解決問題的操作,當問題中涉及的資料範圍非常大,但是實際使用到的資料是比較少的。並且問題的求解是和它範圍裡的其它資料有關係的,那麼可以將這些可能使用到的資料放到一起,排序去重,就將它們對映到了乙個新的較小的範圍裡。例如,下面幾個數是在 infty,infty 範圍裡的,實際用到的數 6...