ACM入门之【线段树】
生活随笔
收集整理的這篇文章主要介紹了
ACM入门之【线段树】
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
線段樹是算法競賽中常用的用來維護(hù) 區(qū)間信息 的數(shù)據(jù)結(jié)構(gòu)。
線段樹可以在 O(logN)的時(shí)間復(fù)雜度內(nèi)實(shí)現(xiàn)單點(diǎn)修改、區(qū)間修改、區(qū)間查詢(區(qū)間求和,求區(qū)間最大值,求區(qū)間最小值)等操作。
線段樹相對于樹狀數(shù)組代碼較長,但是線段樹較全面,功能性更強(qiáng)。
線段樹的基本分為兩類:
- 單點(diǎn)修改,不需要懶標(biāo)記。
- pushup: 由子節(jié)點(diǎn)向上更新父節(jié)點(diǎn)
- bulild: 一段區(qū)間初始化成線段樹
- modify:修改
- query:查詢
- 區(qū)間修改,需要懶標(biāo)記。
- pushup: 由子節(jié)點(diǎn)向上更新父節(jié)點(diǎn)
- pushdown: 由父節(jié)點(diǎn)向下更新子節(jié)點(diǎn)
- bulild: 一段區(qū)間初始化成線段樹
- modify:修改
- query:查詢
線段樹代碼實(shí)現(xiàn)的兩種方法:
- 結(jié)構(gòu)體來實(shí)現(xiàn),結(jié)構(gòu)體內(nèi)保存了各個(gè)信息。
- 數(shù)組來實(shí)現(xiàn),則需要在寫線段樹函數(shù)的時(shí)候需要額外的維護(hù)信息。
線段樹需要開四倍的原因:
我們不難看出上圖的倒數(shù)第二行最多為n,那么上面就是n-1 那么最后一行最多為2*n 故總共最多為4*n-1
下面我們來具體的看一下線段樹代碼實(shí)現(xiàn)的兩種方法:
用結(jié)構(gòu)體來實(shí)現(xiàn)線段樹:
數(shù)組實(shí)現(xiàn)線段樹:
#include<bits/stdc++.h> using namespace std; const int N=1e5*5+10; int a[N],f[N*4],n,m;//f[i]表示編號為i的區(qū)間的和 void build(int u,int l,int r) {if(l==r){f[u]=a[l];return;}int mid=l+r>>1;build(u*2,l,mid);build(u*2+1,mid+1,r);f[u]=f[u*2]+f[u*2+1]; } void add(int u,int l,int r,int x,int v) {f[u]+=v;if(l==r) return;int mid=l+r>>1;if(x<=mid) add(u*2,l,mid,x,v);else add(u*2+1,mid+1,r,x,v); } int query(int u,int l,int r,int l1,int r1) {if(l==l1&&r==r1) return f[u];int mid=l+r>>1;if(mid>=r1) return query(u*2,l,mid,l1,r1);else if(l1>=mid+1) return query(u*2+1,mid+1,r,l1,r1);else{int sum=0;sum+=query(u*2,l,mid,l1,mid);sum+=query(u*2+1,mid+1,r,mid+1,r1);return sum;} } int main(void) {cin>>n>>m;for(int i=1;i<=n;i++) cin>>a[i];build(1,1,n);for(int i=0;i<m;i++){int op; cin>>op;if(op==1){int x,k; cin>>x>>k;add(1,1,n,x,k);}else{int l,r; cin>>l>>r;cout<<query(1,1,n,l,r)<<endl;}}return 0; }總結(jié)
以上是生活随笔為你收集整理的ACM入门之【线段树】的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ACM入门之【树状数组】
- 下一篇: ACM入门之【线段树习题】