線段樹1是一道線段樹的經典模板題,所涉及的線段樹基礎知識也比較全面,作為線段樹初學者(比如我)的練手題就非常合適。這道題想讓我們完成的是對乙個序列的區間修改和區間查詢。關於這兩個操作,
我們要引入乙個新的東西——lazytag。
關於線段樹的一些基礎寫法在這裡不再多贅述,我主要來講一下有關lazytag的用法和與之相關的push_down函式。
lazytag主要是應用於區間修改的這個操作,主要就是為了在時間複雜度上進一步優化。當我們每次要修改某個區間的值,我們就可以在這個區間的節點上打乙個標記,代表這個位置需要進行的修改,而不
用遍歷到每乙個葉子結點,節約了時間。但是,在進行更新和求值的時候,一定不能忘了先push_down,要不然會炸得很慘。
如果這樣說還是難以理解,我們可以舉個例子:
我們建立如上的一顆線段樹,假設我們要對26這個區間進行修改(一定注意更新之前先把之前的標記下傳並清空)。我們從根節點開始遍歷,發現根節點的左兒子包括26這個區間的一部分,所以我們
就向根節點的左兒子遍歷;接下來我們發現12節點和24節點都包括26節點的部分,所以我們就分別向兩邊遍歷;接下來我們發現34這個節點所維護的區間完全在我們想要更新的區間裡,那麼我們就
沒有必要再向下遍歷,直接更新3~4這個節點的tag並返回即可。對於其他點的處理也是一樣的,在這裡就不一一枚舉了。最後強調的一點就是,在我們想要進行下一次更新或者求區間和的操作時,一定
要把上一次的標記清空。這個一定要記住,否則你做題debug的時候會遭受非常大的折磨。
別看在我上面舉的那個例子好像和直接暴力更新區別不大,但是當你的資料量大起來的時候,這個操作就顯得尤為重要。再說一遍,在更新和求值之前千萬不要忘了標記下放啊!!!
code
#include#include#include#include#include#define maxn 100010
typedef long long ll;
ll n,m,a[maxn];
ll tree[maxn << 2], tag[maxn << 2];
inline int lson(ll x)
inline int rson(ll x)
inline void push_up(ll k)
inline void push_down(ll k,ll l,ll r)
void build(ll k,ll l,ll r)
ll mid = (l + r) >> 1;
build(lson(k), l, mid);
build(rson(k), mid + 1, r);
push_up(k);
return;
}void update(ll k,ll l,ll r,ll cl,ll cr,ll v)
push_down(k, l, r);
ll mid = (l + r) >> 1;
if(cl<=mid)
update(lson(k), l, mid, cl, cr, v);
if(cr>mid)
update(rson(k), mid + 1, r, cl, cr, v);
push_up(k);
return;
}ll query(int k,int l,int r,int ql,int qr)
int main()
else
}return 0;
}
luoguP3372 模板 線段樹 1
emmm 今天gg沒講課,青青姐給我講了線段樹 講得太好了!我們來膜一下!然後我就是來講講我聽完後的感受的,大家重點在於誇青青姐tql 像我這樣的蒟蒻,看到線段樹的第一反應是。行吧,姐給我講講唄。姐太強了!姐太巨了!不愧是我姐!然後我們就來看看線段樹是神馬東西吧 上網找的線段樹。感謝圖源 雖然不知道...
luogu3372 線段樹模板1
題目描述 如題,已知乙個數列,你需要進行下面兩種操作 1.將某區間每乙個數加上x 2.求出某區間每乙個數的和 輸入輸出格式 輸入格式 第一行包含兩個整數n m,分別表示該數列數字的個數和操作的總個數。第二行包含n個用空格分隔的整數,其中第i個數字表示數列第i項的初始值。接下來m行每行包含3或4個整數...
P3372 模板 線段樹 1
線段樹學習 這個題來看,線段樹分為建樹,更新,查詢。1.建樹 void build ll p,ll l,ll r ll mid l r 1 build lson p l,mid build rson p mid 1,r push up sum p void push up sum ll p 這段 的...