藉著題解系統得梳理一下對於線段樹的理解
先建立乙個結構體為下面**實現打基礎
structtreet[1000005];
首先,什麼是線段樹呢?線段樹屬於完全二叉樹,其中每乙個子節點而言,都表示整個序列中的一段子區間。由第一層結點儲存單個元素,每個子節點不斷向自己的父親節點傳遞資訊,而父節點儲存的資訊則是他的每乙個子節點資訊的整合。
用陣列建立這種資料結構(建樹)可以通過如下的遞迴函式來實現:
void bulid(int p,int l,intr)
//否則值等於左結點加右結點
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(intp)}
現在我們就可以愉快地進行資料修改了,從根節點開始搜尋,如果某個結點表示的區間完全包含於要修改的值的範圍,那麼對該結點的值進行上述的懶標記更新。
void change(int p,int x,int y,intz) 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;//
最終的值等於左結點的值+右結點的值
}
到此為止,我們只剩下值的查詢乙個問題,但不用想都能發現,查詢和修改根本沒有什麼區別,通過懶標記同理實現即可。
longlong 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...