下面我們來講解線段樹:
線段樹有許多應用,給出乙個序列,可以在任何乙個區間內找到最大,和最小值。可以求區間和等等等等。那麼應用就不多說了。畢竟能到這裡來的我相信都是為了a題,並且了解線段樹的吧!下面我們來建樹:廢話不多說了。
線段樹是一種二叉搜尋樹,與區間樹相似,它將乙個區間劃分成一些單元區間,每個單元區間對應線段樹中的乙個葉結點。
對於線段樹中的每乙個非葉子節點[a,b],它的左兒子表示的區間為[a,(a+b)/2],右兒子表示的區間為[(a+b)/2+1,b]。因此線段樹是平衡二叉樹,最後的子節點數目為n,即整個線段區間的長度。
void pushup(int rt)
void buildtree(int l,int r,int rt)
int mid=(l+r)>>1;
if(l<=mid)
if(r>mid)
pushup(rt);
return ;
}
下面我們就來貼出完整的**:
#include
#include
#include
using
namespace
std;
int n,t;
int array[100000
<<2];//100000乘4
void pushup(int rt)
void buildtree(int l,int r,int rt)
int mid=(l+r)>>1;
if(l<=mid)
if(r>mid)
pushup(rt);
return ;
}int query(int left,int right,int l,int r,int rt)
int mid=(l+r)>>1;
int res=0;
if(mid>=left)
if(mid1,r,rt<<1|1);
}return res;
}int main()}}
return
0;}
下面很多人就要問了,為什麼開陣列為什麼要開n*4的空間,好,我們來看看這張圖。
由圖可以很生動形象的看出,為什麼很多人開2*n會越界了。圖中的x是節點的總數。但是我不想畫圖又怎麼辦呢?推公式??ok下面是我的乙個朋友推出來的公式!!!
假設n為節點的總數,no代表度為0的節點的總數。n2代表度為2的節點的總數!
由此可得:
倍數= n(max)/no -->no也相當於區間的長度。
n(max)可以看做是乙個滿二叉樹(最好的情況)。n(min)可以看做最後一層只有兩個子節點的樹(最壞的情況)。
|_k代表層數。
把n2消掉後可以得到。no = (n + 1) / 2
n(max)=2^k - 1
n(k-1層以上的節點總數)=2^(k-1) + 1
所以:no = [(2^(k-1)+1)+1]/2
倍數= n(max)/no
化簡可以得到 4- 5/(2^(k-2) + 1 )
-->4-5/(2^(k-1)+2)/2
-->4-5/no
即要開的空間倍數就是4-5/no
線段樹 4n 開四倍空間的原因
一 為何要使用線段樹?對於某一類問題,我們主要關注的是乙個線段或者區間。對於給定區間,更新區間中乙個元素或者乙個區間的值,查詢乙個區間 i,j 的最大值 最小值,或者區間數字和。線段樹不一定滿二叉樹,也不一定是完全二叉樹,但一定是平衡二叉樹,下面是線段樹元素個數n 2 k的情況,是滿二叉樹。下面是線...
線段樹為什麼要開四倍空間
最近在看 具體數學 這篇當做是乙個練習吧。假設我們用乙個陣列來頭輕腳重地儲存乙個線段樹,根節點是1,孩子節點分別是2n,2n 1,那麼,設線段長為l 即 1.l 1 設樹的高度為h,對h,有 h l 1,1 h l 2 l 1 l 1 這是乙個很簡單的遞迴式,並用公式3.11逐次代換,就等到h l ...
線段樹開4N空間證明
線段樹採用陣列儲存時,無疑,其儲存空間利用與其左右子樹定義有關 方式一 方式二 假設定義區間 1 5 的線段樹,很容易看出它們的不同 方式一 方式二 由此初步看來,採用第二種方式定義,可能會在其左邊產生較大的空白區域。實際上也的確如此,為了方便我們的習慣,考慮第一種方式定義情況 對於某一區間 l,r...