題目大意:
題目挺好理解的,就是給你一串數字,然後會在某一區間上,使區間的所有數字都加上乙個數,也就是更新這段區間的數字,最後再進行對某一區間的求值操作。
題目分析:
因為這道題目和我之前剛剛做的那道題目很類似,都是區間段更新的題目,但是有所不同的是,那個題目是直接賦值更新,而這個題目是區間進行加和,不是直接賦值,所以就有一點比較麻煩的是,是否需要對單個葉子節點進行更新,如果更新,無疑要耗費很多的時間,但是如果不更新,又難以處理資料,得到正確的求解。
後來在網上看到了乙個線段樹的很好的思想,就是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 ...