宅男唱著歌 橋邊菇涼

2022-08-20 00:24:15 字數 1883 閱讀 9639

------------恢復內容開始------------

暫無線段樹是所有 rmq 中最常用的資料結構。

功能:區間修改區間查詢。不止最值、求和。只要可遞推的值都可以構造線段樹。

如果區間大小為 n,線段樹有 cnt 個節點,那麼 2n−1≤cnt<4n。

節點對於每個節點 x,和堆類似,父親節點為 x>>1(即 x/2 下取整的位運算方法,位運算方便而且快),左兒子為 x<<1(即 2x),右兒子為 x<<1|1(即 2x+1)。

同時每個節點對應一段區間,所以叫線段樹。節點 1 對應的區間為 1∼n。設乙個節點對應的區間為 l∼r,那麼它的左兒子對應的區間就是 l∼mid,其中 mid=(l+r)>>1,右兒子區間為 mid+1∼r。如果乙個節點對應單點區間,就沒有兒子。

同時每個節點對應乙個值,即該區間的 rmq 值。如果是求最值問題,就表示該區間最大值;如果是求和問題,就表示該區間的和。

操作(單點修改區間查詢)

乙個線段樹是求和還是求最值或者求別的東西,取決於 pushup(k) 函式,其中 k 為節點編號,時間複雜度 o(1)。

void pushup(int k)//求最大值

根據原序列構造初始的線段樹用 build() 函式,單點節點上的值就為單點的值,遞迴從下到上構造,時間複雜度 o(nlogn)。

void build(int k=1,int l=1,int r=n) //單點節點

build(k<<1,l,mid),build(k<<1|1,mid+1,r); //遞迴構造

pushup(k); //遞推

先講單點修改(加上 y),只需與 build() 函式類似的遞迴操作即可,如果到達單點節點,就修改,不走那些跟查詢單點沒關係的區間、別忘了修改完後也要遞推,時間複雜度 o(logn)。

void fix(int x,int y,int k=1,int l=1,int r=n) //單點修改

if(mid>=x) fix(x,y,k<<1,l,mid); //遞迴左兒子

else fix(x,y,k<<1|1,mid+1,r); //遞迴右兒子

pushup(k);//遞推

區間查詢,如果單前節點在查詢區間內,就返回值。否則,遞迴左兒子右兒子,遞推得區間查詢值。時間複雜度 o(logn),因為只會走相關的 logn 個節點。

int fmax(int x,int y,int k=1,int l=1,int r=n)

void build(int k=1,int l=1,int r=n)

build(k<<1,l,mid),build(k<<1|1,mid+1,r);

pushup(k);

void fix(int x,int y,int k=1,int l=1,int r=n)

if(mid>=x) fix(x,y,k<<1,l,mid);

else fix(x,y,k<<1|1,mid+1,r);

pushup(k);

int fmax(int x,int y,int k=1,int l=1,int r=n)using namespace sumtree;

int main(){

scanf("%d%d",&n,&m);

for(int i=1;i<=n;i++)

scanf("%d",a+i);

build();

for(int i=1,x,y,z;i<=m;i++){

scanf("%d%d%d",&x,&y,&z);

if(x==1) fix(y,z);

else printf("%d\n",fmax(y,z));

return 0;

線段樹如果只能單點修改區間查詢,**還這麼長,就沒人用他了。所以可想而知,線段樹還可以區間修改,區間查詢。

------------恢復內容結束------------