日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

线段树之延时标记(区间修改)及lazy思想

發(fā)布時(shí)間:2024/10/6 编程问答 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 线段树之延时标记(区间修改)及lazy思想 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

暴力求解

1.最簡(jiǎn)單的方法是:在主函數(shù)中添加一個(gè)循環(huán)?

進(jìn)行 r-l+1次單點(diǎn)修改實(shí)現(xiàn)區(qū)間修改,對(duì)于單個(gè)元素修改時(shí)間復(fù)雜度為 O(log2(n))
所以對(duì)于單個(gè)區(qū)間修改的時(shí)間復(fù)雜度為 O(n*log(n)),甚至比樸素的模擬算法還慢

for(int p=l;p<=r;++p) UpdateTree(p,value);?

2.延時(shí)標(biāo)記 lazy tag
延時(shí)標(biāo)記就是在遞歸的過程中,如果當(dāng)前區(qū)間被需要,修改的區(qū)間完全覆蓋,那么就要停止遞歸,并且在上面做一個(gè)標(biāo)記?

3.但是這個(gè)信息沒有更新到每個(gè)元素(即葉子結(jié)點(diǎn)),下次查詢的時(shí)候可能沒法得到足夠的信息。之前在一個(gè)區(qū)間上打了一個(gè)標(biāo)記,這個(gè)標(biāo)記不僅是這個(gè)結(jié)點(diǎn)的性質(zhì),此性質(zhì)作用于整個(gè)子樹中,假設(shè)我們另一個(gè)查詢中包含了,當(dāng)前區(qū)間的子孫區(qū)間,這個(gè)標(biāo)記也要對(duì)之后的查詢產(chǎn)生影響

lazy tag?

1.如果對(duì)線段樹進(jìn)行單點(diǎn)更新,都是在葉子節(jié)點(diǎn)中實(shí)現(xiàn),不會(huì)對(duì)后續(xù)節(jié)點(diǎn)產(chǎn)生影響

2.如果當(dāng)前區(qū)間被需要修改的目標(biāo)區(qū)間完全覆蓋,打一個(gè)標(biāo)記?
如果下一次的查詢或更改包含此區(qū)間,那么將這個(gè)標(biāo)記分解,并傳遞給左右兒子

3.延時(shí)標(biāo)記在需要時(shí),才向下傳遞信息,如果沒有用到,則不再進(jìn)行操作
為了完成這種操作,可以在結(jié)構(gòu)體中增加一個(gè)add數(shù)組存儲(chǔ)區(qū)間的延時(shí)變化量

4.通俗的解釋 lazy的意思,比如現(xiàn)在需要對(duì)[a,b]區(qū)間進(jìn)行加 C操作,
那么就從根節(jié)點(diǎn)[1,n]開始調(diào)用update函數(shù)進(jìn)行操作,如果剛好執(zhí)行到一個(gè)子節(jié)點(diǎn)
它的節(jié)點(diǎn)標(biāo)記為 rt,這時(shí) tree[rt].l==l&&tree[rt].r==r這時(shí)我們可以進(jìn)一步
更新此時(shí)rt節(jié)點(diǎn)的sum[rt]的值,sum[rt]+=(ll)c*(r-l+1);

5.關(guān)鍵的地方:如果此時(shí)按照常規(guī)的線段樹的update操作,這時(shí)候還應(yīng)該更新
rt子節(jié)點(diǎn)的sum[]值,而lazy思想恰恰是暫時(shí)不更新rt子節(jié)點(diǎn)的sum[]值,
到此時(shí)就 return,直到下一次需要用到rt子節(jié)點(diǎn)的值得時(shí)候才去更新,
這樣避免許多無用的操作,從而節(jié)省時(shí)間

6.PushUp(rt);通過當(dāng)前節(jié)點(diǎn)rt把值遞歸向上更新到根節(jié)點(diǎn)
PushDown(rt);通過當(dāng)前節(jié)點(diǎn)rt遞歸向下去更新rt子節(jié)點(diǎn)的值

rt表示當(dāng)前子樹的根,也就是當(dāng)前所在的節(jié)點(diǎn)?

解題模板

1.定義結(jié)構(gòu)體來存儲(chǔ)每個(gè)節(jié)點(diǎn)的子節(jié)點(diǎn)數(shù)值的總和,
add用來記錄該節(jié)點(diǎn)的每個(gè)數(shù)值應(yīng)該加多少
tree[i].l,tree[i].r分別表示某個(gè)節(jié)點(diǎn)的左右區(qū)間,都是閉區(qū)間?

__int64 sum[N<<2],add[N<<2]; struct Node {int l,r;int mid(){return (l+r)>>1;} } tree[N<<2];

2.PushUp(rt);通過當(dāng)前節(jié)點(diǎn)rt把值遞歸向上更新到根節(jié)點(diǎn)

void PushUp(int rt) {sum[rt] = sum[rt<<1] + sum[rt<<1|1]; }

3.PushDown(rt);通過當(dāng)前節(jié)點(diǎn)rt遞歸向下去更新rt子節(jié)點(diǎn)的值

rt表示當(dāng)前子樹的根,也就是當(dāng)前所在的節(jié)點(diǎn)?

void PushDown(int rt,int m) {if(add[rt]){add[rt<<1] += add[rt];add[rt<<1|1] += add[rt];sum[rt<<1] += add[rt] * (m - (m>>1));sum[rt<<1|1] += add[rt] * (m>>1);add[rt] = 0;} }

4.建立線段樹

void build(int l,int r,int rt) {tree[rt].l = l;tree[rt].r = r;add[rt] = 0;if(l == r){scanf("%I64d",&sum[rt]);return ;}int m = tree[rt].mid();build(lson);build(rson);PushUp(rt); }

5.update函數(shù),lazy思想主要用于這里

通俗的解釋 lazy的意思,比如現(xiàn)在需要對(duì)[a,b]區(qū)間進(jìn)行加 C操作,
那么就從根節(jié)點(diǎn)[1,n]開始調(diào)用update函數(shù)進(jìn)行操作,如果剛好執(zhí)行到一個(gè)子節(jié)點(diǎn)
它的節(jié)點(diǎn)標(biāo)記為 rt,這時(shí) tree[rt].l==l&&tree[rt].r==r這時(shí)我們可以進(jìn)一步
更新此時(shí)rt節(jié)點(diǎn)的sum[rt]的值,sum[rt]+=(ll)c*(r-l+1);

關(guān)鍵的地方:如果此時(shí)按照常規(guī)的線段樹的update操作,這時(shí)候還應(yīng)該更新
rt子節(jié)點(diǎn)的sum[]值,而lazy思想恰恰是暫時(shí)不更新rt子節(jié)點(diǎn)的sum[]值,
到此時(shí)就 return,直到下一次需要用到rt子節(jié)點(diǎn)的值得時(shí)候才去更新,
這樣避免許多無用的操作,從而節(jié)省時(shí)間

void update(int c,int l,int r,int rt) {if(tree[rt].l == l && r == tree[rt].r){add[rt] += c;sum[rt] += (__int64)c * (r-l+1);return;}if(tree[rt].l == tree[rt].r) return;PushDown(rt,tree[rt].r - tree[rt].l + 1);int m = tree[rt].mid();if(r <= m) update(c,l,r,rt<<1);else if(l > m) update(c,l,r,rt<<1|1);else{update(c,l,m,rt<<1);update(c,m+1,r,rt<<1|1);}PushUp(rt); }

6.query函數(shù),也就是用這個(gè)函數(shù)來求區(qū)間和

第一個(gè)if還是區(qū)間的判斷和前面update的一樣,到這里就可以知道答案了,所以就直接return。

接下來的查詢就需要用到rt子節(jié)點(diǎn)的值了,由于我們用了Lazy操作,這段的數(shù)值還沒有更新,因此我們需要調(diào)用PushDown函數(shù)去更新之,滿足if(add[rt])就說明還沒有更新。

__int64 query(int l,int r,int rt) {if(l == tree[rt].l && r == tree[rt].r){return sum[rt];}PushDown(rt,tree[rt].r - tree[rt].l + 1);int m = tree[rt].mid();__int64 res = 0;if(r <= m) res += query(l,r,rt<<1);else if(l > m) res += query(l,r,rt<<1|1);else{res += query(l,m,rt<<1);res += query(m+1,r,rt<<1|1);}return res; }

線段樹 區(qū)間更新 區(qū)間查詢模板題??POJ3468

?

總結(jié)

以上是生活随笔為你收集整理的线段树之延时标记(区间修改)及lazy思想的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。