樹狀陣列簡單入門

2021-07-12 00:06:42 字數 2680 閱讀 4588

樹狀陣列是乙個查詢和修改複雜度都為log(n)的資料結構。主要用於查詢任意兩位之間的所有元素之和。但是每次只能修改乙個元素的值,不如線段樹的應用範圍廣,但是寫起來比線段樹簡單很多,空間複雜度也會低一點。可以用來解一些像求逆序數的題。

上面這張圖就表示了樹狀陣列與原陣列的關係

c陣列完整的儲存了a的所有的資訊,我們可以通過對c陣列的操作來查詢a陣列的區間和還有修改a陣列的單個元素的值。

c[i] = a[i – 2^k + 1] + … + a[i],k為t在二進位制下末尾0的個數

按照上面的規則c[i]也可以認為是由a[i]向前加和lowbit(i)個a陣列值

lowbit(i)可以用下面的**求出:

int lowbit(int i)

我們可以利用c陣列求出1~n區間內的區間和求解方法如下:

int

sum(int i)

return

sum;

}

先令待求區間和為0,之後在依次加上c[i],c[i-lowbit(i)],c[i-lowbit(i)-lowbit(i-lowbit(i))]….顯然最多加log2(i)次,所以求和的複雜度為o(n)。

為了清楚表示這個過程,用一張**模擬1~8的求和過程

對任意區間[x,y]區間和可以簡單的由sum[y]-sum[x-1]求得。

改變a[i],必須要將包含a[i]的所有c[x]的值都改變掉,如何獲取包含a[i]的c[x]呢?

從圖上可以發現對任意c[i]他的父親節點為c[lowbit(i)+i],顯然我們第乙個要改的值就是c[i],改變c[i]後逐步向上修改

(以a[i]加乙個值為例)**如下:

void add(int i,int

value)

}

解決了上面的三個問題就可以用樹狀陣列解題啦

下面給一道樹狀陣列的題:hdoj1166

c國的死對頭a國這段時間正在進行軍事演習,所以c國間諜頭子derek和他手下tidy又開始忙乎了。a國在海岸線沿直線布置了n個工兵營地,derek和tidy的任務就是要監視這些工兵營地的活動情況。由於採取了某種先進的監測手段,所以每個工兵營地的人數c國都掌握的一清二楚,每個工兵營地的人數都有可能發生變動,可能增加或減少若干人手,但這些都逃不過c國的監視。

**情報局要研究敵人究竟演習什麼戰術,所以tidy要隨時向derek匯報某一段連續的工兵營地一共有多少人,例如derek問:「tidy,馬上匯報第3個營地到第10個營地共有多少人!」tidy就要馬上開始計算這一段的總人數並匯報。但敵兵營地的人數經常變動,而derek每次詢問的段都不一樣,所以tidy不得不每次都乙個乙個營地的去數,很快就精疲力盡了,derek對tidy的計算速度越來越不滿:」你個死肥仔,算得這麼慢,我炒你魷魚!」tidy想:「你自己來算算看,這可真是一項累人的工作!我恨不得你炒我魷魚呢!」無奈之下,tidy只好打**向計算機專家windbreaker求救,windbreaker說:「死肥仔,叫你平時做多點acm題和看多點演算法書,現在嚐到苦果了吧!」tidy說:」我知錯了。。。」但windbreaker已經掛掉**了。tidy很苦惱,這麼算他真的會崩潰的,聰明的讀者,你能寫個程式幫他完成這項工作嗎?不過如果你的程式效率不夠高的話,tidy還是會受到derek的責罵的.

第一行乙個整數t,表示有t組資料。

每組資料第一行乙個正整數n(n<=50000),表示敵人有n個工兵營地,接下來有n個正整數,第i個正整數ai代表第i個工兵營地里開始時有ai個人(1<=ai<=50)。

接下來每行有一條命令,命令有4種形式:

(1) add i j,i和j為正整數,表示第i個營地增加j個人(j不超過30)

(2)sub i j ,i和j為正整數,表示第i個營地減少j個人(j不超過30);

(3)query i j ,i和j為正整數,i<=j,表示詢問第i到第j個營地的總人數;

(4)end 表示結束,這條命令在每組資料最後出現;

每組資料最多有40000條命令

對第i組資料,首先輸出「case i:」和回車,

對於每個query詢問,輸出乙個整數並回車,表示詢問的段中的總人數,這個數保持在int以內。

#include 

#include

#include

using

namespace

std;

const

int max = 50005;

int n;

int c[max];

int lowbit(int i)

void add(int i,int value)

}int sum(int i)

return sum;

}int main()

char command[15];

while(scanf("%s",command)&&command[0]!='e')

if(command[0] == 'a')

if(command[0] == 's')}}

return

0;}

樹狀陣列1 樹狀陣列入門

仔細看一下,發現tree的每乙個節點的高度並不是隨意的,而是由它轉成二進位制之後末尾連續零的數量決定的,連續零的數量加1,就是高度,例如 3 11 零的數量為0,加1等於1,所以它的高度就是1 6 110 零的數量為1,加1等於2,所以它的高度就是2 8 1000 零的數量為3,加1等於4,所以它的...

樹狀陣列 入門

樹狀陣列,乙個用來區間求和修改都為log n 的演算法。在網上資料很多,看起來也不是很難,學習一下!基本上學習樹狀陣列都會看到下面這個圖,這也是最基本的乙個圖,看懂這個以後,對樹狀陣列也就會有 一定的了解了。令這棵樹的結點編號為c1,c2.cn。令每個結點的值為這棵子樹的值的總和,那麼容易發現 c1...

樹狀陣列入門

用office做了一張pdf 這是一維的情形,如果是二維,可以把每一行的一維樹狀陣列看成乙個節點,然後再把二維樹狀陣列看成一維樹狀陣列。好文章 兩道入門題 對於第一題hdu1556 題意 初始陣列元素值都為0,給定區間 x,y 將區間 x,y 每個元素的值 1,最後輸出整個陣列每個元素的值。更新區間...