線段樹學習筆記

2021-07-06 06:40:59 字數 3026 閱讀 5963

線段樹是一種

二叉搜尋樹

,與區間樹

相似,它將乙個區間劃分成一些單元區間,每個單元區間對應線段樹中的乙個葉結點。

使用線段樹可以快速的查詢某乙個節點在若干條線段中出現的次數,時間複雜度為o(logn)。而未優化的

空間複雜度

為2n,因此有時需要離散化讓空間壓縮。

以下筆記摘自lcomyn神犇部落格(

1.以單點更新,求區間最小值為例

自下而上更新:

[cpp]view plain

copy

void

updata(

inti)  

建樹:  

void

build(

inti,

intl,

intr)

//建立區間為[l,r](注意為閉區間)

build(i*2,l,(l+r)/2);//建立左子樹(注意區間範圍)

build(i*2+1,(l+r)/2+1,r);//建立右子樹(注意區間範圍)

updata(i);//更新節點資訊,注意先查詢後更新。

}  

單點更新:

[cpp]view plain

copy

void

insert(

inti,

intl,

intr,

intx,

inty)  

mid=(l+r)/2;  

if(x<=mid)  

insert(i*2,l,mid,x,y);//在左子樹

else

insert(i*2+1,mid+1,r,x,y);//在右子樹

updata(i);//更新}

2.對於

單點更新

線段樹中第幾個非空葉節點(如joseph問題,poj2828 buy tickets等)

,我們可以用node[i].value來記錄該區間有幾個非空節點,查詢時比較x與node[i*2].value即可。

[cpp]view plain

copy

void

insert(

inti,

intl,

intr,

intx)  

if(x<=node[i*2])

//左子樹中

insert(i*2,l,mid,x);  

else

//右子樹中,注意減去左子樹中數目。

insert(i*2+1,mid+1,r,x-node[i*2]);  

updata(i);  

}   

處理[x,y]詢問(ps:由於x,y不發生改變,亦可用全域性變數)  

void

query(

inti,

intl,

intr,

intx,

inty)

//在節點i的[l,r]區間內查詢[x,y]

mid=(l+r)/2;  

if(x<=mid)

//左子樹有交集

query(i*2,l,mid,x,y);  

if(y>mid)

//右子樹有交集

query(i*2+1,mid+1,r,x,y);  

}   

對於區間修改(給區間整體加減乘實數除乙個定值),區間查詢類問題,我們可以對每乙個節點設定乙個delta,記錄更新值,而不進行實質性更新,每當查詢或詢問到此節點時,在對delta進行下放,下放至左右子樹,這樣就保證了程式的效率;

建樹,自下而上更新**相同

1.區間修改,區間最值:

釋放標記 

[cpp]view plain

copy

void

paint(

inti,

inta)  

標記下放 

[cpp]view plain

copy

void

pushdown(

inti)  

區間更新[x,y]

[cpp]view plain

copy

void

insert(

inti,

intl,

intr,

intx,

inty,

inta)  

pushdown(i);//標記下放。

if(x<=mid)  

insert(i*2,l,mid,x,y,a);  

if(y>mid)  

insert(i*2+1,mid+1,r,x,y,a);  

updata(i);  

}  

處理[x,y]詢問(ps:由於x,y不發生改變,亦可用全域性變數)

void query(int i,int l,int r,int x,int y)//在節點i的[l,r]區間內查詢[x,y]

[cpp]view plain

copy

pushdown(i); //標記下放

mid=(l+r)/2;  

if(x<=mid)

//左子樹有交集

query(i*2,l,mid,x,y);  

if(y>mid)

//右子樹有交集

query(i*2+1,mid+1,r,x,y);  

}   

2.值得一提的是,當區間最值改為區間求和時,node[i]應加上a*區間長度,所以paint和pushdown應多傳遞l和r兩變數,對value值進行修改時 node[i].value+=a;改為node[i].value+=a*(r-l+1);value值不變

3.對於給區間中的每乙個值開平方抑或乘方等(即更新值不同),只能立即對標記下放至葉節點,但必須對更新條件加以判斷,否則tle

線段樹學習筆記

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

線段樹學習筆記

線段樹是一種維護區間的資料結構,且滿足二叉樹的全部性質 下圖是一棵維護區間 1 6 1,6 的線段樹 格式 idl ri dl r我們可以發現,對於每個節點 k k 來說,其左節點編號為2k role presentation style position relative 2k2 k,右節點編號為...

線段樹學習筆記

線段樹的構造 void build node cur,int l,int r else cur leftchild cur rightchild null 線段樹的查詢 int query node cur,int l,int r 線段樹的延遲修改 void change node cur,int ...