樹狀數組

下面是我自己對樹狀數組的認識。。。

樹狀數組,是一個查詢和修改複雜度都爲log(n)的數據結構。樹狀數組支持區間查詢,單值修改。樹狀數組之所以查詢快速,是因爲相當於對數組有效的劃分和維護。

這圖是盜的度孃的。。。C數組就是樹狀數組。

C[1]=A[1];

C[2]=A[1]+A[2];

C[3]=A[3];

C[4]=A[1]+A[2]+A[3]+A[4];

C[5]=A[5];

C[6]=A[5]+A[6];

C[7]=A[7];

C[8]= A[1]+A[2]+A[3]+A[4]+A[5]+A[6]+A[7]+A[8];

..........

C數組每一個元素都有一個維護長度(也就是管轄範圍),假設元素C[x]維護長度爲l,則元素表示的是從A[x-l+1]到A[x]的所有元素和。因此,樹狀數組的建立主要在於每個元素的維護長度的求解。對於結點編號爲x的結點,假設它的二進制表示形式末尾有t個連續的0,那麼該結點的維護長度就是2^t。也就是說,該元素表示的是從A[x-2^t+1]到A[x]的所有元素和。

而對於給定的x,它的二進制表示形式末尾0的個數t可用一個短小精悍的公式求出:k=(x)&(-x)。 這公式研究不了,直接用了。。。

int lowbit(int x)   
{
    return x&(-x);
}

所以,可以得出計算前k項元素和的算法。

int sum(int k)
{
    int ans = 0;
    while(k>0)
    {
        ans += c[k];
        k = k- lowbit(k);
    }
    return ans;
}

如果要求的不是從頭開始的某段元素的和,可以利用減法。比如求的是A[m]到A[n]之間元素的和,可以S(n)-S(m-1)求出。

而對於單值的更新,要將其關聯的所有C數組中元素的值全部更新。下面對A[t]的值更新。

void add(int t,int value)
{
    while(t<=n)
    {
        c[t] += value;
        t = t + lowbit(t);
    }
}

最後就是C數組的初始建立了。

void build()
{
    for (int i=1;i<=n;i++)
    {
        c[i]=A[i];
        for (int j=i-1; j>i-lowbit(i);j-=lowbit(j))
            c[i]+=c[j];
    }
}

注意C[i]的管轄範圍。。。

總之,樹狀數組就是通過管轄範圍(下標維護)來提高效率的。

void build()
{
    for (int i=1;i<=n;i++)
    {
        c[i]=A[i];
        for (int j=i-1; j>i-lowbit(i);j-=lowbit(j))
            c[i]+=c[j];
    }
}


 

 

發佈了43 篇原創文章 · 獲贊 8 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章