要學樹狀陣列的先看懂一幅圖
這就是樹狀陣列的儲存方式。
那麼樹狀陣列的優點是什麼呢,允許任意修改,可快速提取出a陣列內數字
據圖可知
c1=a1,
c2=a1+a2,
c3=a3,
c4=a1+a2+a3+a4,
c5=a5,
c6=a5+a6,
c7=a7,
c8=a1+a2+a3+a4+a5+a6+a7+a8,
c9=a9,
c10=a9+a10,
c11=a11.......
.c16=a1+a2+a3+a4+a5+.......+a16。
分析上面的幾組式子可知,當 i 為奇數時,ci=ai ;當 i 為偶數時,就要看 i 的因子中最多有二的多少次冪,例如,6 的因子中有 2 的一次冪,等於 2 ,所以 c6=a5+a6(由六向前數兩個數的和),4 的因子中有 2 的兩次冪,等於 4 ,所以 c4=a1+a2+a3+a4(由四向前數四個數的和)。
(一)因此得到公式 cn=a(n-a^k+1)+.........+an(其中 k 為 n 的二進位制表示中從右往左數的 0 的個數)。
那麼,如何求 a^k 呢?求法如下:
1int lowbit(intx)2
為啥那?
以68為例,他的二進位制是(68)2=1000100. 那麼-68呢?因為計算機裡的整數採用補碼表示(補碼是原碼取反加一),因此-68實際上是68按位取反,末尾加一以後的結果。如下表(忽略符號位):
原碼 1 0 0 0 1 0 0
↓反碼 0 1 1 1 0 1 1
↓補碼 0 1 1 1 1 0 0
我們把(68)2和(-68)2放在一起看一看:
1 0 0 0 1 0 0
0 1 1 1 1 0 0
發現他們末尾帶的0是一樣多的。因此lowbit(x)=x&-x. (&是轉換成二進位制之後進行與運算;而&&是直接進行與運算)
(二)由此,我們就可以求出c陣列了
1(三)當陣列中的元素有變更時,樹狀陣列就發揮它的優勢了,演算法如下(修改為給某個節點 i 加上 x ):int sum(intx)2
9 }
1嗯。就這樣。不算難。大概就是一種可變更的儲存方式吧void change(int i,intx)2
8 }
演算法 樹狀陣列
演算法適用於求前k個整數的和,一般的做法是設定乙個sum陣列來表示 1 問題公升級一下 在查詢的過程中隨時給第x個整數加上乙個整數v,同樣要求查詢第k個整數的和。此時若還是原來的sum陣列,則要遍歷來更新,複雜度為o n 而用樹狀陣列則時間要更快。2 再來一題 很簡單的,別怕昂 計算序列中在元素左邊...
演算法 樹狀陣列
相信大家都會樹狀陣列的 單點修改,區間查詢 或者 區間修改,單點查詢 博主就不細講了。但是博主今天發現了乙個神奇的演算法 博主太菜 它可以使用樹狀陣列維護 區間修改,區間查詢 就是乙個優化過的字首和,使查詢和修改協調為 theta log 2n namespace fentree void add ...
演算法(十三)樹狀陣列
問題描述 小蔥喜歡除法,所以他給了你n個數a1,a2,an,並且希望你執行m次操作,每次操作可能有以下兩種 給你三個數l,r,v,你需要將al,al 1,ar之間所有v的倍數除以v。給你兩個數l,r,你需要回答al al 1 ar的值是多少。輸入格式 第一行兩個整數n,m,代表數的個數和操作的次數。...