P3372 線段樹模版1

2022-05-16 11:27:14 字數 1313 閱讀 9107

藉著題解系統得梳理一下對於線段樹的理解

先建立乙個結構體為下面**實現打基礎

struct

treet[1000005];

首先,什麼是線段樹呢?線段樹屬於完全二叉樹,其中每乙個子節點而言,都表示整個序列中的一段子區間。由第一層結點儲存單個元素,每個子節點不斷向自己的父親節點傳遞資訊,而父節點儲存的資訊則是他的每乙個子節點資訊的整合。

用陣列建立這種資料結構(建樹)可以通過如下的遞迴函式來實現:

void bulid(int p,int l,int

r)

//否則值等於左結點加右結點

int mid=l+r>>1

; bulid(p*2

,l,mid);

bulid(p*2+1,mid+1

,r);

t[p].pre=t[p*2].pre+t[p*2+1

].pre;

}

那麼,當資料結構已經建成,我們怎樣對其中的資料進行修改和查詢呢?

這裡要借助一種工具:懶標記。懶標記的作用是記錄每次、每個節點要更新的值。由於每個父節點下面都連著子節點,父節點和子節點需要同時實現值的更新。因此,懶標記從最初的父節點開始表示,在父節點值更新後,把子節點的懶標記更新為父節點懶標記,父節點本身懶標記為0。光說可能難以理解,請看**:

void spread(int

p)}

現在我們就可以愉快地進行資料修改了,從根節點開始搜尋,如果某個結點表示的區間完全包含於要修改的值的範圍,那麼對該結點的值進行上述的懶標記更新。

void change(int p,int x,int y,int

z) spread(p);

//如果發現沒有被覆蓋,那就需要繼續向下找,將懶標記下放

int mid=t[p].l+t[p].r>>1

;

if(x<=mid) change(p*2,x,y,z);//

如果要修改的區間覆蓋了左結點,就修改左結點

if(y>mid) change(p*2+1,x,y,z);//

右結點同理

t[p].pre=t[p*2].pre+t[p*2+1].pre;//

最終的值等於左結點的值+右結點的值

}

到此為止,我們只剩下值的查詢乙個問題,但不用想都能發現,查詢和修改根本沒有什麼區別,通過懶標記同理實現即可。

long

long ask(int p,int x,int

y)

穿在一起,就構成了線段樹的基本操作了

p3372 線段樹模版

題目鏈結 對樣例的樹這樣畫w 從上到下標區間 0 4 這個是tree 0 2 是tree 3 4 是tree 0 1 是tree 是tree 是tree 是tree 是tree 是tree 接下來的都是空結點 然後看 叭 include using namespace std define max ...

P3372 模板 線段樹 1

線段樹學習 這個題來看,線段樹分為建樹,更新,查詢。1.建樹 void build ll p,ll l,ll r ll mid l r 1 build lson p l,mid build rson p mid 1,r push up sum p void push up sum ll p 這段 的...

P3372 模板 線段樹 1

題 include includeusing namespace std typedef long long ll ll n,m,ans,x,y,op,val 因為下面有的函式需要用到x,y,val值,懶得傳參,故直接寫為全域性變數 const int n 100000 struct nodetre...