今天也就重點看了下樹狀陣列,下面來記一些基礎知識以及和線段樹的對比
主要用於查詢任意兩位之間的所有元素之和,但是每次只能修改乙個元素的值;
經過簡單修改可以在log(n)的複雜度下進行範圍修改,但是這時只能查詢其中乙個元素的值(如果加入多個輔助陣列則可以實現區間修改與區間查詢)。
能用樹狀陣列解決的問題,基本上都能用線段樹解決,而線段樹能解決的樹狀陣列不一定能解決。相比較而言,樹狀陣列效率要高很多。
令這棵樹的結點編號為c1,c2...cn。令每個結點的值為這棵樹的值的總和,那麼容易發現:
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
...c16 = a1 + a2 + a3 + a4 + a5 + a6 + a7 + a8 + a9 + a10 + a11 + a12 + a13 + a14 + a15 + a16
為什麼呢!!!!
很容易知道c8表示a1~a8的和,但是c6卻是表示a5~a6的和,為什麼會產生這樣的區別的呢?或者說發明她的人為什麼這樣區別對待呢?
答案是,這樣會使操作更簡單!看到這相信有些人就有些感覺了,為什麼複雜度被log了呢?可以看到,c8可以看作a1~a8的左半邊和+右半邊和,而其中左半邊和是確定的c4,右半邊其實也是同樣的規則把a5~a8一分為二……繼續下去都是一分為二直到不能分樹狀陣列巧妙地利用了二分,樹狀陣列並不神秘,關鍵是巧妙!
樹狀陣列的基礎就是乙個被構造出來的式子:c[i]=a[i]+a[i-1]+....+a[i-2^k+1];k代表i的二進位制的最後連續0的個數 比如 對於1000和101000,k=3。
用c++來實現樹狀陣列
#include
using namespace std;
int n,m,i,num[100001],t[200001],l,r;//num:原陣列;t:樹狀陣列
int lowbit(int x)
void change(int x,int p)//將第x個數加p
return;
}int sum(int k)//前k個數的和
return ans;
}int ask(int l,int r)//求l-r區間和
int main()
for(i=1;i<=m;i++)
{cin>>l>>r;
cout/
//明天繼續樹狀陣列,再看些例題估計就能應用了
訓練日記 20161024
初賽好像不會掛了,好開心!版權原因,不上傳題目。題意 求1 n n 1000 的排列中逆序對恰好為 k 個的排列數目。多測。題解 f i j 表示前 i 個數,逆序對個數恰好為 j的排列個數,易得轉移方程f i j i 1k 0f i 1 j k 用字首和優化可使複雜度降為o n2 題意 對於乙個長...
訓練日記 20170324
長久不更新部落格了。期間經歷了恰好被ag線踩的wc,經歷了漫長痛苦的小高考準備。現在終於可以重整旗鼓,向省選進發!幾個月來,唯一不變的是我仍然是個超級蒟蒻 版權原因,不上傳題目。題意 最小樹形圖 去年就接觸 聽說 過的演算法,一直沒有真正寫過。因為各種奇怪的細節錯誤,調了好幾個小時 比如找環時沒有判...
訓練日記 20170328
今天的題目似乎很水 好多人都提前ak離場了,於是提前一小時收題。但是我還是各種不會。思維江化?話說,聽到一句很有趣的話 山不在高,有林則徐 水不在深,有江 題意 給定一棵有n n 105 個節點的有根樹,編號互不重複。詢問有多少棵子樹內節點編號構成乙個連續區間。題解 水題,對於每個節點 i 記錄以該...