標記永久化

2022-05-27 10:39:13 字數 2544 閱讀 5013

1 概述

在可持久化線段樹中,我們常常要使用區間修改操作。這時候,如果再用下傳標記再向上更新的方式(pushdown&pushup)來實現就會變得十分麻煩(因為要可持久化嘛)。

那麼,有沒有一種實現線段樹區間修改的方式可以不用下傳標記或向上更新呢?有,那就是標記永久化。

2 原理

標記永久化的原理簡單來說就是修改時一路更改被影響到的點,詢問時則一路累加路上的標記,從而省去下傳標記的操作。

3 **實現

3.0 說明

這裡以區間修改區間求和的線段樹為例。

線段樹中編號為p的結點的值和標記分別為val[p]和mark[p]。

3.1 建樹

標記永久化線段樹的建樹和標記不永久化線段樹的建樹沒有什麼區別,這裡就不在贅述,直接上**吧。

void build(int p,int l,int

r)

int mid=(l+r)>>1

; build(p

<<1,l,mid);//

遞迴建左子樹

build(p<<1|1,mid+1,r);//

遞迴建右子樹

val[p]=val[p<<1]+val[p<<1|1];//

這裡是要向上更新一下的

}

3.2 區間修改

0.設要將區間[x,y]中的數都加上v。

1.一路走下去同時更新路上受此次修改影響的節點的值,即val[p]+=(y-x+1)*v。

2.當目前結點所代表的區間與待修改區間完全重合時,更新標記,返回,即mark[p]+=v;

void add(int p,int l,int r,int x,int y,long

long

v)//

更新標記

int mid=(l+r)>>1

;

if(y<=mid) add(p<<1

,l,mid,x,y,v);

else

if(x>mid) add(p<<1|1,mid+1

,r,x,y,v);

else add(p<<1,l,mid,x,mid,v),add(p<<1|1,mid+1,r,mid+1

,y,v);

}

有人可能會問:標記更新後直接返回的話下面的結點不就沒更新了嗎?

慢慢來嘛,往下看就明白啦。

3.3 區間詢問

0.設要要區間[x,y]中的數的總和。

1.一路走下去同時累加路上的標記,因為在修改操作中標記並沒有下傳,所以要這樣子,即ad+=mark[p]。

2.當目前結點所代表的區間與待修改區間完全重合時,返回當前結點的值與累加下來的標記乘上詢問區間長度的和,即return val[p]+(y-x+1)*ad。

int ask(int p,int l,int r,int x,int y,int ad)//

ad為一路上累加的標記

4 練習題

luogu p3372 【模板】線段樹1

**:

#include#include

using

namespace

std;

long

long val[400005],mark[400005

];void build(int p,int l,int

r)

int mid=(l+r)>>1

; build(p

<<1

,l,mid);

build(p

<<1|1,mid+1

,r);

val[p]=val[p<<1]+val[p<<1|1];}

void add(int p,int l,int r,int x,int y,long

long

v)

int mid=(l+r)>>1

;

if(y<=mid) add(p<<1

,l,mid,x,y,v);

else

if(x>mid) add(p<<1|1,mid+1

,r,x,y,v);

else add(p<<1,l,mid,x,mid,v),add(p<<1|1,mid+1,r,mid+1

,y,v);

}long

long ask(int p,int l,int r,int x,int y,long

long

ad)int

main()

else printf("

%lld\n

",ask(1,1,n,x,y,0

)); }

return0;

}

5 參考資料

標記永久化

標記永久化是線段樹的乙個技巧,常用於無法 或難以 進行 pushdown 的較複雜的資料結構如主席樹,樹套樹等。如何做?對每個節點維護 sum 和 add 考慮修改,當詢問與當前區間重合時,更新 add val 對所有經過的區間 sum val cdot r l 1 void modify int ...

線段樹標記永久化

對於樹套樹,主席樹等使用到線段樹的比較複雜的資料結構,如果區間修改的話,打標記後pushdown或者pushup是很難做到的完全不行吧 所以這個時候,乙個神奇的東西誕生了。線段樹標記永久化,維護乙個標記,假設為cov,再維護乙個sum 假設修改區間 ql,qr 全部加上v 和平常一樣,到這個區間後c...

線段樹 標記永久化

一般線段樹做區間修改操作時,先是找到目標區間,然後修改該區間,並打下延遲標記,最後從目標區間自底向上,更新所有包含目標區間的區間的值 即pushup 當該區間子節點被訪問前,pushdown下推標記。這種維護區間的方式存在一點點弊端。例如用這種方式寫一棵可持久化線段樹,因為每次pushdown都相當...