線段樹是一種
二叉搜尋樹
,與區間樹
相似,它將乙個區間劃分成一些單元區間,每個單元區間對應線段樹中的乙個葉結點。
使用線段樹可以快速的查詢某乙個節點在若干條線段中出現的次數,時間複雜度為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 ...