財神娛樂首存即享優惠回饋唷~詳情請進👉

『數據布博奕局』線段樹

線段樹道理

線段樹,相似區間樹,它在各個節點保管一條線段(數組中的一段子數組),首要用于高效辦理延續區間的靜態查問成績,因為二叉布局的特征,它根本能堅持每個操作的龐大度為\(O(logn)\)。

線段樹的每個節點透露表現一個區間,子節點則分手透露表現父節點的擺布半區間,例如父親的區間是\([a,b]\),那末\((c=(a+b)/2)\)左兒子的區間是\([a,c]\),右兒子的區間是\([c+1,b]\)。

上面咱們從一個經典的例子來相識線段樹,成績描寫以下:從數組a[0…n-1]中查找某個數組某個區間內的最小值,個中數組地下539坐車巨細固定,然則數組中的元素的值可以隨時更新。

對這個成績一個簡略的解法是:遍歷數組區間找到最小值,時間龐大度是\(O(n)\),額定的空間龐大度\(O(1)\)。當數據量分外大,而查問操作很頻仍的時辰,耗時可能會不知足需求。

另一種解法:使用一個二維數組來保管提早計算好的區間\([i,j]\)內的最小值,那末預處置時間為\(O(n^2)\),查問耗時\(O(1)\),然則必要額定的\(O(n^2)\)空間,當數據量很大時,這個空間損耗是復雜的,并且當改變了數組中的某一增加偏財運的方法個值時,更新二維數組中的最小值也很貧苦。

咱們可以用線段樹來辦理這個成績:預處置耗時\(O(n)\),查問、更新操作\(O(logn)\),必要額定的空間\(O(n)\)。依據這個成績咱們組織以下的二叉樹

葉子節點是原始組數\(a\)中的元素
非葉子節點代表它的一切子孫葉子節點地點區間的最小值
例如關于數組\([2,5,1,4,9,3]\)可以組織以下的二叉樹(違景為白色透露表現葉子節點,非葉子節點的值是其對應數組區間內的最小值,例如根節點透露表現數組區間\(a[0…5]\)內的最小值是1):

因為線段樹的父節點區間是均勻宰割到擺布子樹,是以線段樹是齊全二叉樹,關電競運彩下注于包括\(n\)個葉子節點的齊全二叉樹,它肯定有\(n-1\)個非葉節點,統共\(2n-1\)個節點,是以存儲線段是必要的空間龐大度是\(O(n)\)。那末線段樹的操作:創立線段樹、查問、節點更新 是若何運作的呢(如下一切代碼都是針對求區間最小值成績)?

關于線段樹咱們可以選擇以及平凡二叉樹同樣的鏈式布局。因為線段樹是齊全二叉樹,咱們也能夠用數組來存儲,上面的接頭及代碼都是數組來存儲線段樹,節點布局以下(注重到用數組存儲時,有用空間為\(2n-1\),現實空間確不止這么多,譬如下面的線段樹中葉子節點\(1\)、\(3\)固然沒有擺布子樹,然則切實其實占用了數組空間,現實空間是滿二叉樹的節點數量。

線段樹的代碼完成

建線段樹的進程

void build(int l,int r,int root)
{
    if (l==r)
    {
        sum[root]=a[l];
        return;
    }
    int mid=(l+r)>>1;
    build(l,mid,root<<1);
    build(mid+1,r,root<<1|1);
    pushup(root);
}

pushup進程

void push(int root)
{
    sum[root]=sum[root<<1]+s線上 捕 魚 機um[root<<1|1];
}

查問線段樹

int query(int ansl,int ansr,int l,int root)
{
    if (ansl<=l && r<=ansr) return sum[root];
    int mid=(l+r)>>1;
    int ans=0;
    if (ansl<=mid) ans+=query(ansl,ansr,l,root<<1);
    if (ansr>mid) ans+=query(ansl,mid+1,root<<1|1);
    return ans;
}

單節點更新

void update(int pos,int c,int root)
{
    if (l==r)
    {
        sum[root]+=c;
       地下539玩法 return;
    }
    int mid=(l+r)/2;
    if (pos<=mid) update(pos,c,root<<1); else update(pos,root<<1|1);
    pushup(root);
}

【免責聲明】本站內容轉載自互聯網,其相關談吐僅代表作者小我私家概念盡非權勢巨子,不代表本站態度。如您發明內容存在版權成績,請提交相關鏈接至郵箱:,咱們將實時予以處置。