線段樹摘要

2021-08-15 10:09:03 字數 3159 閱讀 3957

看了大牛的線段樹講解,受益匪淺,無奈篇幅太長,自己總結了一下其中比較重要的要點:

摘自:線段樹是用陣列來模擬樹形結構,對於每乙個節點r ,左子節點為 2*r (一般寫作r<<1)右子節點為 2*r+1(一般寫作r<<1|1)

然後以1為根節點,所以,整體的統計資訊是存在節點1中的。

這麼表示的原因看下圖就很明白了,左子樹的節點標號都是根節點的兩倍,右子樹的節點標號都是左子樹+1:

線段樹需要的陣列元素個數是:

遞迴實現線段樹:

#define maxn 100007  //元素總個數  

#define ls l,m,rt<<1

#define rs m+1,r,rt<<1|1

int sum[maxn<<2],add[maxn<<2];//sum求和,add為懶惰標記

int a[maxn],n;//存原陣列資料下標[1,n]

建樹

//pushup函式更新節點資訊 ,這裡是求和  

void pushup(int rt)

//build函式建樹

void build(int l,int r,int rt)

int m=(l+r)>>1;

//左右遞迴

build(l,m,rt<<1);

build(m+1,r,rt<<1|1);

//更新資訊

pushup(rt);

}

點修改假設a[l]+=c:

void update(int l,int c,int l,int r,int rt)  

int m=(l+r)>>1;

//根據條件判斷往左子樹呼叫還是往右

if(l <= m) update(l,c,l,m,rt<<1);

else update(l,c,m+1,r,rt<<1|1);

pushup(rt);//子節點更新了,所以本節點也需要更新資訊

}

區間修改:假設a[l,r]+=c

void update(int l,int r,int c,int l,int r,int rt)  

int m=(l+r)>>1;

pushdown(rt,m-l+1,r-m);//下推標記

//這裡判斷左右子樹跟[l,r]有無交集,有交集才遞迴

if(l <= m) update(l,r,c,l,m,rt<<1 if="" r=""> m) update(l,r,c,m+1,r,rt<<1|1);

pushup(rt);//更新本節點資訊

}

區間查詢:

詢問a[l,r]的和

首先是下推標記的函式:

void pushdown(int rt,int ln,int rn)  

}

然後是區間查詢的函式:

int query(int l,int r,int l,int r,int rt)  

int m=(l+r)>>1;

//下推標記,否則sum可能不正確

pushdown(rt,m-l+1,r-m);

//累計答案

int ans=0;

if(l <= m) ans+=query(l,r,l,m,rt<<1 if="" r=""> m) ans+=query(l,r,m+1,r,rt<<1|1);

return ans;

}

函式呼叫

//建樹   

build(1,n,1);

//點修改

update(l,c,1,n,1);

//區間修改

update(l,r,c,1,n,1);

//區間查詢

int ans=query(l,r,1,n,1);

非遞迴實現線段樹:

#define maxn 100007  

int a[maxn],n,n;//原陣列,n為原陣列元素個數 ,n為擴充元素個數

int sum[maxn<<2];//區間和

int add[maxn<<2];//懶惰標記

建樹

void build(int n)  

}

點修改

void update(int l,int c)  

}

點修改下的區間查詢:求a[l..r]的和(點修改沒有使用add所以不需要考慮)

**非常簡潔,也不難理解,

s和t分別代表之前的論述中的左右藍色節點,其餘的**根據之前的論述應該很容易看懂了。

s^t^1 在s和t的父親相同時值為0,終止迴圈。

兩個if是判斷s和t分別是左子節點還是右子節點,根據需要來計算sum

int query(int l,int r)  

return ans;

}

區間修改:a[l..r]+=c

//  

void update(int l,int r,int c)

//更新上層sum

for(;s;s>>=1,t>>=1)

}

區間修改下的區間查詢:求a[l..r]的和

int query(int l,int r)  

//處理上層標記

for(;s;s>>=1,t>>=1)

return ans;

}

結合強哥講課的內容,發現線段樹很好理解,就是**稍微複雜點而已,感覺很ok沒有想象中的困難

線段樹 02 構建線段樹

public inte ce merger 不能再縮小的基本問題是 對treeindex指向的節點的情況進行討論 public class segmenttree 在treeindex的位置建立表示區間 l.r 的線段樹 private void buildsegmenttree int treei...

線段樹 01 線段樹基礎

物理上 public class segmenttree public int getsize public e get int index 返回完全二叉樹的陣列表示中,乙個索引所表示的元素的左孩子節點的索引 private int leftchild int index 返回完全二叉樹的陣列表示中...

線段樹和zkw線段樹

好啦,我們就開始說說線段樹吧 線段樹是個支援區間操作和查詢的東東,平時的話還是蠻實用的 下面以最基本的區間加以及查詢區間和為例 線段樹顧名思義就是棵樹嘛,葉子節點是每個基本點,它們所對應的父親就是它們的和,具體如下圖 但是對於這樣的線段樹來說,操作所需的時間是遠達不到我們的要求的 會被t 因為我們會...