線段樹基礎與模板與簡單應用

2021-08-07 01:54:08 字數 4057 閱讀 9463

參考自

線段樹,類似區間樹,它在各個節點儲存一條線段(陣列中的一段子陣列),主要用於高效解決連續區間的動態查詢問題,由於二叉結構的特性,它基本能保持每個操作的複雜度為o(logn)。

線段樹的每個節點表示乙個區間,子節點則分別表示父節點的左右半區間,例如父親的區間是[a,b],那麼(c=(a+b)/2)左兒子的區間是[a,c],右兒子的區間是[c+1,b]。(父節點從0開始的情況)

由於線段樹的父節點區間是平均分割到左右子樹,因此線段樹是完全二叉樹,對於包含n個葉子節點的完全二叉樹,它一定有n-1個非葉節點,總共2n-1個節點,因此儲存線段是需要的空間複雜度是o(n)。

#include

#include

#include

using

namespace

std;

const

int infinite = int_max;

const

int maxnum = 1000;

struct segtreenode

segtree[maxnum]; //定義線段樹

/* 功能:構建線段樹

root:當前線段樹的根節點下標

arr: 用來構造線段樹的陣列 就是葉子節點的值val陣列

istart:陣列的起始位置

iend:陣列的結束位置

*/void build(int root,int arr,int istart,int iend)}/*

功能:當前節點的標誌域向孩子節點傳遞

root: 當前線段樹的根節點下標

*/void pushdown(int root)}/*

功能:線段樹的區間查詢

root:當前線段樹的根節點下標

[nstart, nend]: 當前節點所表示的區間

[qstart, qend]: 此次查詢的區間

*/int query(int root, int nstart, int nend, int qstart, int qend)

/*功能:更新線段樹中某個區間內葉子節點的值

root:當前線段樹的根節點下標

[nstart, nend]: 當前節點所表示的區間

[ustart, uend]: 待更新的區間

addval: 更新的值(原來的值加上addval)

*/void update(int root,int nstart,int nend,int ustart,int uend,int addval) //以增加值為例

//涉及到子樹了,延遲生效

pushdown(root);

//更新左右結點

int mid = (nstart + nend) / 2;

update(root*2+1, nstart, mid, ustart, uend, addval);

update(root*2+2, mid+1, nend, ustart, uend, addval);

//根據左右子樹的值回溯更新當前節點的值

segtree[root].val = min(segtree[root*2+1].val, segtree[root*2+2].val);

}

描述

lily特別喜歡養花,但是由於她的花特別多,所以照料這些花就變得不太容易。她把她的花依次排成一行,每盆花都有乙個美觀值。如果lily把某盆花照料的好的話,這盆花的美觀值就會上公升,如果照料的不好的話,這盆花的美觀值就會下降。有時,lily想知道某段連續的花的美觀值之和是多少,但是,lily

的算術不是很好,你能快速地告訴她結果嗎?

輸入

第一行乙個整數t,表示有t組測試資料。

每組測試資料的第一行為乙個正整數n (n<=50000),表示lily有n盆花。

接下來有n個正整數,第i個正整數ai (1<=ai<=50) 表示第i盆花的初始美觀值。

接下來每行有一條命令,命令有4種形式:

(1)add i j, i和j為正整數,表示第i盆花被照料的好,美觀值增加j (j<=30)

(2)sub i j, i和j為正整數,表示第i盆花被照料的不好,美觀值減少j (j<=30)

(3)query i j, i和j為正整數,i<=j,表示詢問第i盆花到第j盆花的美觀值之和

(4)end,表示結束,這條命令在每組資料最後出現

每組資料的命令不超過40000條

輸出

對於第i組資料,首先輸出」case i:」和回車。

對於每個」query i j」命令,輸出第i盆花到第j盆花的美觀值之和。

樣例輸入

1

97 9 8 4 4 5 4 2 7

query 7 9

add 4 9

query 3 6

sub 9 6

sub 3 3

query 1 9

end

樣例輸出

case 1:

1330

50

#include

#include

#include

#include

using

namespace

std;

const

int infinite = int_max;

const

int maxnum = 200010;

int arr[maxnum];

struct segtreenode

segtree[maxnum]; //定義線段樹

/* 功能:構建線段樹

root:當前線段樹的根節點下標

arr: 用來構造線段樹的陣列 就是葉子節點的值val陣列

istart:陣列的起始位置

iend:陣列的結束位置

*/void build(int root,int istart,int iend)}/*

功能:當前節點的標誌域向孩子節點傳遞

root: 當前線段樹的根節點下標

*/void pushdown(int root)}/*

功能:線段樹的區間查詢

root:當前線段樹的根節點下標

[nstart, nend]: 當前節點所表示的區間

[qstart, qend]: 此次查詢的區間

*/int query(int root, int nstart, int nend, int qstart, int qend)

/*功能:更新線段樹中某個區間內葉子節點的值

root:當前線段樹的根節點下標

[nstart, nend]: 當前節點所表示的區間

[ustart, uend]: 待更新的區間

addval: 更新的值(原來的值加上addval)

*/void update(int root,int nstart,int nend,int ustart,int uend,int addval) //以增加值為例

//涉及到子樹了,延遲生效

pushdown(root);

//更新左右結點

int mid = (nstart + nend) / 2;

update(root*2+1, nstart, mid, ustart, uend, addval);

update(root*2+2, mid+1, nend, ustart, uend, addval);

//根據左右子樹的值回溯更新當前節點的值

segtree[root].val = segtree[root*2+1].val + segtree[root*2+2].val;

} int main()

else

if(com[0] == 's')

else

if(com[0] == 'q')}}

return

0; }

線段樹基礎模板

c國的死對頭a國這段時間正在進行軍事演習,所以c國間諜頭子derek和他手下tidy又開始忙乎了。a國在海岸線沿直線布置了n個工兵營地,derek和tidy的任務就是要監視這些工兵營地的活動情況。由於採取了某種先進的監測手段,所以每個工兵營地的人數c國都掌握的一清二楚,每個工兵營地的人數都有可能發生...

簡單線段樹模板

入門第四天,前三天的沒時間補,回去再慢慢寫吧。今天學長講的是線段樹,講得很有老師的感覺.然後就是講的也都差不多聽懂了,只是有些細節在寫 的時候沒有注意到,一直錯。需要注意的點 1.在build的時候在left right時是node u a left 之前老是錯寫成node left a left ...

簡單線段樹(模板)

hdu 1754 模板,單點更新,區間查詢 1 include 2 include 3 include 4 include 5 include 6 include 7 include 8 include 9 include 10 include 11 include 12 define lson l...