線段樹是一種二叉搜索樹,與區間樹類似,它將一個區間劃分紅一些單元區間,每一個單元區間對應線段樹中的一個葉結點。
使用線段樹能夠快速的查找某一個節點在若干條線段中出現的次數,時間複雜度爲O(logN)。而未優化的空間複雜度爲2N,實際應用時通常還要開4N的數組以避免越界,所以有時須要離散化讓空間壓縮。
單點
修改模板(維護區間和)
void build(int le,int ri,int k,int v,int pl)
{ d[k]+=v;
if(le==ri)return;
int mid=(le+ri)>>1;
if(mid>=pl)
build(le,mid,k*2,v,pl);
else
build(mid+1,ri,k*2+1,v,pl);
}
區間查詢模板(維護區間和)
int visit(int le,int ri,int k,int x,int y)
{ //if(le>y||ri<x)return 0;
//cout<<k<<' '<<d[k]<<endl;
if(le>=x&&y>=ri)return d[k];
int mid=(le+ri)>>1;
int ans=0;
if(mid>=x)ans+=visit(le,mid,k*2,x,y);
if(mid<y){
ans+=visit(mid+1,ri,k*2+1,x,y);
//cout<<mid<<' '<<1<<endl;
}
return ans;
}
單點修改模板(維護區間最大值)(特別鳴謝計蒜客ls)
void build(int k,int l,int r,int pl,int v)
{ if(l==r){
d[k]=v;
return;
}
int mid=(l + r)>>1;
if(mid>=pl){
build(k*2,l,mid,pl,v);
}
else {
build(k*2+1,mid+1,r,pl,v);
}
d[k]=max(d[k*2],d[k*2+1]);
}
區間查詢模板(維護區間最大值)
int visit(int le,int ri,int k,int x,int y)
{ if(le>=x&&ri<=y){
return d[k];
}
int mid=(le+ri)>>1;
int maxn=-1;
if(mid>=x)maxn=max(maxn,visit(le,mid,k*2,x,y));
if(mid<y)maxn=max(maxn,visit(mid+1,ri,k*2+1,x,y));
return maxn;
}
例題
有一種神奇斑點蛇,蛇如其名,全身都是斑點,斑點數量能夠任意改變。ui
有一天,蒜頭君十分的無聊,開始數蛇上的斑點。假設這條蛇的長度是 Ncm,蒜頭君已經數完開始時蛇身的第 icm 上有 ai個i 個斑點。spa
如今蒜頭君想知道這條斑點蛇的任意區間的蛇身上一共有多少個斑點。這好像是一個很容易的事情,可是這條蛇好像是和蒜頭君過不去,老是刻意的改變蛇身上的斑點數量。code
因而,蒜頭君受不了了,加上蒜頭君有密集型恐懼症。聰明又能幹的你能幫幫他嗎?htm
輸入格式
第一行一個正整數 N(N≤50000)表示這條斑點蛇長度爲 N 釐米,接下來有 N 個正整數,第 i 個正整數 aii 表明第 iii 個斑點蛇第 iii 釐米開始時有 aia_iai 個斑點(1≤ai≤501\leq a_i\leq 501≤ai≤50)。ip
接下來每行有一條命令,命令有 4 種形式:get
(1) Add i j,i 和 j爲正整數,表示第 i 釐米增長 j 個斑點(j 不超過 30);it
(2) Sub i j,i 和 j 爲正整數,表示第 i釐米減小 j 個斑點(j 不超過 30);
(3) Query i,j,i 和 j 爲正整數,i≤j,表示詢問第 i 到第 j 釐米的斑點總數(包括第 i 釐米和第 j 釐米);
(4) End 表示結束,這條命令在每組數據最後出現;
最多有 40000 條命令。
輸出格式
對於每一個 Query 詢問,輸出一個整數並回車,表示詢問的段中的總斑點數,這個數保證在int
範圍內。
樣例輸入
10
1 2 3 4 5 6 7 8 9 10
Query 1 3
Add 3 6
Query 2 7
Sub 10 2
Add 6 3
Query 3 10
End
樣例輸出
6
33
59
分析
裸的線段樹,代碼嗎......,看模板吧