線段樹基礎

2022-06-22 17:39:09 字數 1876 閱讀 9241

1:概述

線段樹,類似區間樹,是乙個完全二叉樹,它在各個節點儲存一條線段(陣列中的一段子陣列),主要用於高效解決連續區間的動態查詢問題,由於二叉結構的特性,它基本能保持每個操作的複雜度為o(lgn)!

性質:父親的區間是[a,b],(c=(a+b)/2)左兒子的區間是[a,c],右兒子的區間是[c+1,b],線段樹需要的空間為陣列大小的四倍。

2:基本操作(demo用的是查詢區間最小值)

線段樹的主要操作有:

(1):線段樹的構造 void build(int node, int begin, int end);

主要思想是遞迴構造,如果當前節點記錄的區間只有乙個值,則直接賦值,否則遞迴構造左右子樹,最後回溯的時候給當前節點賦值

#include using namespace std;  

const int maxind = 256;

int segtree[maxind * 4 + 10];

int array[maxind];

/* 建構函式,得到線段樹 */

void build(int node, int begin, int end)

}

int main()

//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);

}

(2)點修改:

假設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);//子節點的資訊更新了,所以本節點也要更新資訊

}

點修改其實可以寫的更簡單,只需要把一路經過的sum都+=c就行了,不過上面的**更加規範,在題目更加複雜的時候,按照格式寫更不容易錯。

(3)區間查詢(本題為求和):

詢問a[l..r]的和

注意到,整個函式的遞迴過程中,l,r是不變的。

首先如果當前區間[l,r]在[l,r]內部,就直接累加答案

如果左子區間與[l,r]有重疊,就遞迴左子樹,右子樹同理。

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

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

//左子區間:[l,m] 右子區間:[m+1,r] 求和區間:[l,r]

//累加答案

int ans=0;

if(l <= m) ans+=query(l,r,l,m,rt<<1);//左子區間與[l,r]有重疊,遞迴

if(r > m) ans+=query(l,r,m+1,r,rt<<1|1); //右子區間與[l,r]有重疊,遞迴

return ans;

}

**:

線段樹 01 線段樹基礎

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

線段樹 基礎

d 基礎 time limit 1000msmemory limit 32768kb64bit io format i64d i64u submit status description c國的死對頭a國這段時間正在進行軍事演習,所以c國間諜頭子derek和他手下tidy又開始忙乎了。a國在海岸線沿...

線段樹基礎

寫得不錯啊。前段時間寫了篇 搞懂樹狀陣列 如果說樹狀陣列是優雅的,那麼線段樹就是萬能的。有句話就叫 樹狀陣列能做的線段樹都能做,但是樹狀陣列能做的堅決用樹狀陣列!因為線段樹本來的內容狠豐富的,主要有單點跟新 區間跟新,最值詢問 區間詢問 反正就是對於區間進行的動態跟新詢問都能較高效的完成。對於初學者...