在此我們之前學習了線段樹的單點更新(點我
)。但是現在我們遇到乙個這樣的問題:
給出乙個n個元素的陣列a1,a2,...,an。我們總共進行m次操作。每次操作為下列兩種操作其中一種:
1、add(l, r, v): 將a(l), a(l+1),...,a(r)的值全部增加v。
2、query(l, r): 計算子串行a(l), a(l+1),...,a(r)的元素和,最小值和最大值。
注意:a(l),括號為下標。
如果我們採用單點更新,我們不難發現每一次都對區間中的每乙個點單獨更新,那麼效率會及其低下。我們要如何既保證效率,有完成整個區間的更新呢?於是某個大牛想到了延遲標記的方法,也就是我們今天要學習的區間更新。
何為延遲標記呢?從字面理解,延遲標記那就延遲更新的標記。那麼怎麼做到延遲更新呢?我們舉個例子來說明,假設我們現在有乙個長度為8的序列,ai表示第i個元素。
如果我們執行了add(3, 6, 4)操作,那麼我們只將[5, 8]這個區間進行標記,而不繼續往下更新,如圖:
從圖中我們可以看出,延遲標記只在對應的區間內設定了乙個標記,並沒有進行更新。那麼在什麼時候進行更新呢?在查詢該區間或者下一次對該區間的元素更新的時候,我們才進行更新。
我們從這個例子可以發現延遲標記的作用:延遲的標記的加入,使得線段樹只對使用到的區間進行更新,沒有用到的得區間不更新。這樣處理之後,線段樹的效率又有了進一步的提高。
介紹完原理之後我們來談一談**實現吧。
//add陣列為延遲標記陣列
//sum儲存線段樹的陣列
//sum[i]表示編號為i的區間所對應的區間和
//初始化,sum,add都為0既可
int sum[n], add[n];
//將標記移至下一層
void pushdown(int i, int lft, int rht)
}//對區間[qft, qrht]同時加addval
//i為區間編號,[lft, rht]為編號i對應的區間
void update(int i, int lft, int rht, int qlft, int qrht, int addval)
else
}//查詢區間[qft, qrht]的和
//i,lft, rht解釋同update。
int query(int i, int lft, int rht, int qlft, int qrht)
到此我們已經介紹完線段樹的區間更新了,區間最值的**實現類似在此不再敘述。
大家可以來一道水題練練手(poj 3468 a ****** problem with integers
)。提示本題有個坑(資料範圍)!
線段樹(區間更新求和)
poj 3468 include using namespace std define max 100100 struct node 求區間長度 int get dis node tree max 3 long long d max 建樹 long long build int left,int r...
線段樹之區間更新
為什麼這樣?答案是顯然的。線段樹的查詢和單點更新的時間複雜度是o logn 的,如果我每次都只是更新乙個節點,再去詢問,那麼複雜度是o nlogn 這個複雜度是可以接受的,但是如果每次操作我都是更新乙個區間,還是用單點更新去做,那麼複雜度是o n 2logn 這個複雜度是很大的,一般來說,在acm競...
線段樹 區間更新 模版
include include cstdio include string.h using namespace std const int n 100005 struct node tree n 4 int n,m int a n void init 將下面更新的值返回上一層 void pushup...