線段樹基礎詳解

2022-04-27 17:31:29 字數 3421 閱讀 5689

儲存結構是怎樣的?

線段樹是一種二叉樹,當然可以像一般的樹那樣寫成結構體,指標什麼的。

但是它的優點是,它也可以用陣列來實現樹形結構,可以大大簡化**。

陣列形式適合在程式設計競賽中使用,在已經知道線段樹的最大規模的情況下,直接開足夠空間的陣列,然後在上面建立線段樹。

簡單的記法: 足夠的空間 = 陣列大小n的四倍。 

實際上足夠的空間 =  (n向上擴充到最近的2的某個次方)的兩倍。

舉例子:假設陣列長度為5,就需要5先擴充成8,8*2=16.線段樹需要16個元素。如果陣列元素為8,那麼也需要16個元素。

所以線段樹需要的空間是n的兩倍到四倍之間的某個數,一般就開4*n的空間就好,如果空間不夠,可以自己算好最大值來省點空間。

怎麼用陣列來表示一顆二叉樹呢?假設某個節點的編號為v,那麼它的左子節點編號為2*v,右子節點編號為2*v+1。

然後規定根節點為1.這樣一顆二叉樹就構造完成了。通常2*v在**中寫成 v<<1 。 2*v+1寫成 v<<1|1 。

以下以維護數列區間和的線段樹為例,演示最基本的線段樹**。

(0)定義:

#define maxn 100007  //

元素總個數

#define ls l,m,rt<<1

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

intsum[maxn<<2],add[maxn<<2];

//sum

求和,add

為懶惰標記

inta[maxn],n;

//存原陣列資料下標

[1,n] 

(1)   建樹:

(2)

//pushup

函式更新節點資訊

,這裡是求和

(3)voidpushup(intrt)  

(4)

//build

函式建樹

(5)voidbuild(intl,intr,intrt)  

(10)intm=(l+r)>>1;  

(11)     

//左右遞迴

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

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

(14)     

//更新資訊

(15)          pushup(rt);  

(16)      }  

(2)點修改:

假設a[l]+=c:

1.voidupdate(intl,intc,intl,intr,intrt)  

6.intm=(l+r)>>1;  

7.  

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

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

9.elseupdate(l,c,m+1,r,rt<<1|1);  

10.     pushup(rt);//

子節點更新了,所以本節點也需要更新資訊

11. }   

(3)區間修改:

voidupdate(intl,intr,intc,intl,intr,intrt)  

intm=(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);

//更新本節點資訊

}   

(4)區間查詢:

詢問a[l,r]的和

首先是下推標記的函式:

1.voidpushdown(intrt,intln,intrn)  

13. }  

然後是區間查詢的函式:

intquery(intl,intr,intl,intr,intrt)  

intm=(l+r)>>1;  

//下推標記,否則

sum可能不正確

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

//累計答案

intans=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);  

returnans;  

}   

(5)函式呼叫:

//建樹

build(1,n,1);   

//點修改

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

//區間修改

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

//區間查詢

intans=query(l,r,1,n,1);  

線段樹基礎詳解

儲存結構是怎樣的?線段樹是一種二叉樹,當然可以像一般的樹那樣寫成結構體,指標什麼的。但是它的優點是,它也可以用陣列來實現樹形結構,可以大大簡化 陣列形式適合在程式設計競賽中使用,在已經知道線段樹的最大規模的情況下,直接開足夠空間的陣列,然後在上面建立線段樹。簡單的記法 足夠的空間 陣列大小n的四倍。...

線段樹 詳解

acm刷題時遇到許多連續區間的動態查詢問題,例如求取某一區間上元素之和 求取某一區間上元素的最大值,此時如果使用一般的方法求解會使得時間超出要求。此時需要使用到線段樹,其主要用於高效解決連續區間的動態查詢問題。線段樹,類似區間樹,是乙個完全二叉樹,它在各個節點儲存一條線段 陣列中的一段子陣列 由於二...

線段樹詳解

線段樹是處理區間問題的好的解決方法,當有n個元素時對區間的操作可以在o logn 時間內完成,有q個詢問也不會超時,根據節點維護的資料的不同,線段樹可以提供不同的功能,下面以rang minimum query rmq,即查詢區間內最小值 為例,進行說明。對於陣列,線段樹結構為 其維護區間與儲存下標...