------------恢復內容開始------------
暫無線段樹是所有 rmq 中最常用的資料結構。
功能:區間修改區間查詢。不止最值、求和。只要可遞推的值都可以構造線段樹。
如果區間大小為 n,線段樹有 cnt 個節點,那麼 2n−1≤cnt<4n。
節點對於每個節點 x,和堆類似,父親節點為 x>>1(即 x/2 下取整的位運算方法,位運算方便而且快),左兒子為 x<<1(即 2x),右兒子為 x<<1|1(即 2x+1)。
同時每個節點對應一段區間,所以叫線段樹。節點 1 對應的區間為 1∼n。設乙個節點對應的區間為 l∼r,那麼它的左兒子對應的區間就是 l∼mid,其中 mid=(l+r)>>1,右兒子區間為 mid+1∼r。如果乙個節點對應單點區間,就沒有兒子。
同時每個節點對應乙個值,即該區間的 rmq 值。如果是求最值問題,就表示該區間最大值;如果是求和問題,就表示該區間的和。
操作(單點修改區間查詢)
乙個線段樹是求和還是求最值或者求別的東西,取決於 pushup(k) 函式,其中 k 為節點編號,時間複雜度 o(1)。
void pushup(int k)//求最大值
根據原序列構造初始的線段樹用 build() 函式,單點節點上的值就為單點的值,遞迴從下到上構造,時間複雜度 o(nlogn)。
void build(int k=1,int l=1,int r=n) //單點節點
build(k<<1,l,mid),build(k<<1|1,mid+1,r); //遞迴構造
pushup(k); //遞推
先講單點修改(加上 y),只需與 build() 函式類似的遞迴操作即可,如果到達單點節點,就修改,不走那些跟查詢單點沒關係的區間、別忘了修改完後也要遞推,時間複雜度 o(logn)。
void fix(int x,int y,int k=1,int l=1,int r=n) //單點修改
if(mid>=x) fix(x,y,k<<1,l,mid); //遞迴左兒子
else fix(x,y,k<<1|1,mid+1,r); //遞迴右兒子
pushup(k);//遞推
區間查詢,如果單前節點在查詢區間內,就返回值。否則,遞迴左兒子右兒子,遞推得區間查詢值。時間複雜度 o(logn),因為只會走相關的 logn 個節點。
int fmax(int x,int y,int k=1,int l=1,int r=n)
void build(int k=1,int l=1,int r=n)
build(k<<1,l,mid),build(k<<1|1,mid+1,r);
pushup(k);
void fix(int x,int y,int k=1,int l=1,int r=n)
if(mid>=x) fix(x,y,k<<1,l,mid);
else fix(x,y,k<<1|1,mid+1,r);
pushup(k);
int fmax(int x,int y,int k=1,int l=1,int r=n)using namespace sumtree;
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%d",a+i);
build();
for(int i=1,x,y,z;i<=m;i++){
scanf("%d%d%d",&x,&y,&z);
if(x==1) fix(y,z);
else printf("%d\n",fmax(y,z));
return 0;
線段樹如果只能單點修改區間查詢,**還這麼長,就沒人用他了。所以可想而知,線段樹還可以區間修改,區間查詢。
------------恢復內容結束------------