在了解單點更新的線段樹的前提下,再繼續理解區間更新的線段樹。
區間更新是指更新某個區間內的葉子節點的值,因為涉及到的葉子節點不止乙個,而葉子節點會影響其相應的非葉父節點,那麼回溯需要更新的非葉子節點也會有很多,如果一次性更新完,操作的時間複雜度肯定不是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思想
題目大意 題目挺好理解的,就是給你一串數字,然後會在某一區間上,使區間的所有數字都加上乙個數,也就是更新這段區間的數字,最後再進行對某一區間的求值操作。題目分析 因為這道題目和我之前剛剛做的那道題目很類似,都是區間段更新的題目,但是有所不同的是,那個題目是直接賦值更新,而這個題目是區間進行加和,不是...