學習筆記 線段樹基礎和應用

2022-10-10 22:36:19 字數 3062 閱讀 2830

給出乙個區間[1,5],我們將它二分,mid=(1+5)/2=3,左區間[l,mid]=[1,3],右區間[mid+1,r]=[4,5]。

又將左區間二分,mid=(1+3)/2=2,左區間的左區間是[1,2],右區間是[2,3],又二分,直到分到l==r為止,以此類推,我們建乙個樹。

我們建立這樣的一棵二叉樹,而且除了葉子節點外,是一棵滿二叉樹,那麼我們可以把它們的下標輕鬆寫出來,像這樣:

可以看出,父節點為i,那麼左兒子就是i2(i<<1),右兒子是i2+1(i<<1|1),這樣就表示出了每乙個點的下標了。我們發現這一棵二叉樹,那麼它的空間是很大的,所以我們開tree[maxn]要是序列數的至少4倍才不會爆。

題目描述:給出乙個序列,可以對它的某個點更新,查詢某個區間的max。

要讓我們單點更新,區間求max。那麼我們來分步驟解釋此題。

1.建樹

對於它給的初始值我們建立出線段樹。

在這裡,我用#define lc k<<1,#define rc k<<1|1,表示左右兒子

struct

node

t[n<<2]

;//開4倍大小

inline

void

build

(int k,

int l,

int r)

//k是下標,l是該節點的區間的左節點,r是右節點

int mid=

(l+r)

>>1;

build

(lc,l,mid)

;//遞迴建樹左右兒子

build

(rc,mid+

1,r)

; t[k]

.mx=

max(t[lc]

.mx,t[rc]

.mx)

;//回溯回來更新最大值

}

2.單點更新

要更新點,我們肯定要去找到這個點,還是用遞迴的方法找。

inline

void

update

(int k,

int x,

int val)

int mid=

(t[k]

.l+t[k]

.r)>>1;

if(x<=mid)

update

(lc,x,val)

;//在左區間找

else

update

(rc,x,val)

;//在右區間找

t[k]

.mx=

max(t[lc]

.mx,t[rc]

.mx)

;//更新

}

3.查詢

查詢某個區間的最大值,考慮是否線段樹的區間包含了這個區間或這個區間跨越了多個線段樹的區間。

inline

intquery

(int k,

int l,

int r)

這樣我們就已經完成了這個題目。

下面我們來看一道新的題。

lazy_tag懶惰標記,如果有乙個題,要讓我們區間更新,區間求和。每次更新我們都要更改這裡面所有的值,而有些值我們可能更新了卻不查詢,那就白白浪費了時間,所以我們引入lazy_tag來進行標記,等到要用這個點後才去更新,(的確很懶) ,那麼我們來看看**實現。

如果我更新了遇到了標記,那麼我就把標記向2個左右兒子傳,並取消自己的標記。

傳送門luogup3372

我們還是分步驟進行

1.建樹

struct

node

t[n<<2]

;

inline

void

build

(int k,

int l,

int r)

int mid=

(l+r)

>>1;

build

(lc,l,mid)

;build

(rc,mid+

1,r)

; t[k]

.w=t[lc]

.w+t[rc]

.w;//改為求和

}

2.更新

更新就要用到lazy_tag了。

另外還要乙個函式pushdown來處理lazy_tag。

ps:#define ll long long

inline

void

pushdown

(int k)

}

inline

void

update

(int k,

int l,

int r,

int v)

pushdown

(k);

//下傳標記

int mid=

(t[k]

.l+t[k]

.r)>>1;

if(l<=mid)

update

(lc,l,r,v);if

(r>mid)

update

(rc,l,r,v)

; t[k]

.w=t[lc]

.w+t[rc]

.w;}

3.查詢

查詢也差不多,仍然要更新標記。

ll query

(int k,

int l,

int r)

最後我們就完美的解決了這道題。

線段樹還有很多功能,任重而道遠 。

線段樹的基礎應用

大約為葉子節點的4倍 線段樹父節點的資訊可以利用up 從子節點提取的 同時線段樹樹上可以通過down 將父節點的資訊給子節點 void tree int l,int r,int p void build int l,int r,int p 以求區間和為例 void update int x,int ...

線段樹學習筆記

線段樹是一種 二叉搜尋樹 與區間樹 相似,它將乙個區間劃分成一些單元區間,每個單元區間對應線段樹中的乙個葉結點。使用線段樹可以快速的查詢某乙個節點在若干條線段中出現的次數,時間複雜度為o logn 而未優化的 空間複雜度 為2n,因此有時需要離散化讓空間壓縮。以下筆記摘自lcomyn神犇部落格 1....

線段樹學習筆記

本文筆記在參考一步一步理解線段樹 tenos的基礎上形成 線段樹,也是二叉搜尋樹的一種,是基於陣列,但是優於陣列的一種資料結構。同時結合預處理 時間複雜度一般在o n 使得從原來陣列的o n 的查詢和更新複雜度降到了o logn 在處理很大資料量的資料更新和查詢最值方面變得簡單,值得一提的是,它的構...