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

2021-07-23 22:30:28 字數 1609 閱讀 2066

題目大意:

題目挺好理解的,就是給你一串數字,然後會在某一區間上,使區間的所有數字都加上乙個數,也就是更新這段區間的數字,最後再進行對某一區間的求值操作。

題目分析:

因為這道題目和我之前剛剛做的那道題目很類似,都是區間段更新的題目,但是有所不同的是,那個題目是直接賦值更新,而這個題目是區間進行加和,不是直接賦值,所以就有一點比較麻煩的是,是否需要對單個葉子節點進行更新,如果更新,無疑要耗費很多的時間,但是如果不更新,又難以處理資料,得到正確的求解。

後來在網上看到了乙個線段樹的很好的思想,就是lazy思想,簡單來說,就是首先更新父節點,當恰好屬於父節點的時候,可以直接得出答案,否則再次向下更新子節點。分別有兩個函式,乙個是pushup(),是向上更新父節點。乙個是pushdown(),是向下更新子節點。

這個lazy思想主要是用在update裡的。if(tree[rt].l == l && r == tree[rt].r) 這裡就是用到lazy思想的關鍵時刻 正如上面說提到的,這裡首先更新該節點的sum[rt]值,然後更新該節點具體每個數值應該加多少即add[rt]的值,注意此時整個函式就執行完了,直接return,而不是還繼續向子節點繼續更新,這裡就是lazy思想,暫時不更新子節點的值。

那麼什麼時候需要更新子節點的值呢?答案是在某部分update操作的時候需要用到那部分沒有更新的節點的值的時候,這裡可能有點繞口。這時就掉用pushdown()函式更新子節點的數值。

接下來的查詢就需要用到rt子節點的值了,由於我們用了lazy操作,這段的數值還沒有更新,因此我們需要呼叫pushdown函式去更新之,滿足if(add[rt])就說明還沒有更新。

#include#include#include#include#includeusing namespace std;

#define ll long long

#define lson l,mid,rt*2

#define rson mid+1,r,rt*2+1

#define maxn 100000+10

ll sum[maxn<<2];

ll add[maxn<<2];

void pushup(int rt)

void pushdown(int rt,int m) }

void build(int l,int r,int rt)

int mid=( l + r )/2;

build(lson);

build(rson);

pushup(rt);

}void update(int l,int r,int c,int l,int r,int rt)

pushdown(rt,r-l+1);

int mid = ( l+r ) / 2;

if(l<=mid)

update(l,r,c,lson);

if(r>mid)

update(l,r,c,rson);

pushup(rt);

}ll query(int l,int r,int l,int r,int rt)

int main()

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

} return 0;

}

以上的有很多是學習這篇部落格的

POJ 3468 線段樹區間

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

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

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

POJ 3468《線段樹,區間add

題目連線 位運算 k 1 相當於 k 2 k 1 1 相當於 k 2 1 修改區間內的值,並且維護區間和。詳見 include include include using namespace std typedef long long ll const int maxn 100000 10 int ...