線段樹區間更新(以POJ 3468為例)

2021-07-25 13:49:09 字數 2603 閱讀 4364

在了解單點更新的線段樹的前提下,再繼續理解區間更新的線段樹。

區間更新是指更新某個區間內的葉子節點的值,因為涉及到的葉子節點不止乙個,而葉子節點會影響其相應的非葉父節點,那麼回溯需要更新的非葉子節點也會有很多,如果一次性更新完,操作的時間複雜度肯定不是o(lgn)。為此引入了線段樹中的延遲標記概念,這也是線段樹的精華所在。

延遲標記:每個節點新增加乙個標記,記錄該節點是否進行了某種修改。將指定更新區間在樹上找到對應節點後,給這些節點打上標記。在查詢時,如果當前節點有標記,就給它的子節點打上該標記,並刪除當前節點的標記。

延遲標記除了能夠記錄某個節點的是否進行修改外,通常也記錄修改的情況,方便在查詢時直接能夠得到修改的結果。

struct node
對於區間更新的線段樹,通常有四個功能:

build:左右遞迴建樹,初始化每個節點sum值。同時將每個節點的延遲標記設定為0。

pushdown:將父節點的延遲標記傳遞給子節點(如果題意需要,還要將父節點的值傳給子節點),同時將父節點的延遲標記清空。

query:對指定區間查詢,左右子樹遞迴查詢。查詢時如果父節點有延遲標記,需要向下傳遞。

update:對指定區間更新,左右子樹遞迴更新。當更新到指定區間時,加上父節點的延遲標記(如果題意需要,還要進行其他操作),返回。如果沒有更新到指定區間,就繼續更新,如果過程中有節點有延遲標記,需要向下傳遞。最後回溯更新父節點的值。

注意:

update時,只有指定區間會有延遲標記,並且此時指定區間和它的父區間的sum已經更改,它的子區間和其他區間沒有延遲標記和修改值。

query時,延遲標記會傳至子區間,並且同時修改子區間的值,直到找到指定區間。此時,延遲標記在指定區間上,指定區間的子區間的sum值沒有修改。

對於poj 3468:

在pushdown和update時,子區間需要加上父區間傳過來的值*區間元素數;

(具體操作見**)

#include 

#include

#include

#include

using

namespace

std;

typedef

long

long ll;

const

int n=1e5+10;

ll a[n];

char opr[10];

struct nodetree[4*n];

void build(ll i,ll l,ll r)

ll tmp=i<<1;

ll mid=(l+r)>>1;

build(tmp,l,mid);//左子樹

build(tmp+1,mid+1,r);//右子樹

tree[i].sum=tree[tmp].sum+tree[tmp+1].sum;//回溯得到區間sum值

}void pushdown(ll x)

ll query(ll i,ll l,ll r)

if(tree[i].l>=l&&tree[i].r<=r)

//如果查詢時發現當前區間不為目標區間,但是有延遲標記時,將延遲標記傳遞

if(tree[i].add) pushdown(i);

ll tmp=i<<1;

//左右子樹分別查詢,將查詢結果相加

//如果某一子樹超出範圍,會在第乙個條件處return 0

return query(tmp,l,r)+query(tmp+1,l,r);

}void update(ll i,ll l,ll r,ll s)

//在指定區間的範圍內,該點加上sum與延遲標記.此時包含該點的父區間均更新完畢

//>=、<=是考慮到區間位於不同子樹的情況

if(tree[i].l>=l&&tree[i].r<=r)

//如果之前已經有延遲標記,需要將之前的標記處理

if(tree[i].add) pushdown(i);

ll tmp=i<<1;

//更新左右子樹,如果某個子樹超出了所更新區間的範圍,會在第乙個條件處return

update(tmp,l,r,s);

update(tmp+1,l,r,s);

tree[i].sum=tree[tmp].sum+tree[tmp+1].sum;//回溯更新父節點的值

}int main()

build(1,1,n);

ll l,r,s;

while(q--)

}}}/*

10 5

1 2 3 4 5 6 7 8 9 10

q 4 4

q 1 10

q 2 4

c 3 6 3

q 2 4

5 10

1 2 3 4 5

c 3 5 2

q 3 5

*/

POJ 3468 線段樹區間

這個題目是第二個區間修改的線段樹了,做到現在可以發現線段樹真的非常的靈活,特別是區間修改部分,前面的單點修改其實還是也可參看模版的,區間修改就真的非常靈活了了。這個題目就是區間加法,然後求乙個累加和,同樣地也是需要乙個延遲標誌的,也就是lazy,然後還需要乙個統計當前區間的全部和的陣列。就可以輕鬆解...

poj 3468 線段樹 區間和,有更新

題意 給定q 1 q 100,000 個數a1,a2 aq,以及可能多次進行的兩個操作 1 對某個區間ai aj的每個數都加n n可變 2 求某個區間ai aj間所有數的和 思路 線段樹。注意每次更新不更新到葉節點,只更新到完整的區間為止。具體為 增加時如果改變的區間正好覆蓋乙個節點,則增加其節點的...

poj 3468 線段樹區間更新 lazy思想

題目大意 題目挺好理解的,就是給你一串數字,然後會在某一區間上,使區間的所有數字都加上乙個數,也就是更新這段區間的數字,最後再進行對某一區間的求值操作。題目分析 因為這道題目和我之前剛剛做的那道題目很類似,都是區間段更新的題目,但是有所不同的是,那個題目是直接賦值更新,而這個題目是區間進行加和,不是...