早就想著把以前搞acm的演算法複習一遍,那可是瑰寶啊,一直沒時間,之前面實習就有此感慨,以前學的演算法都忘了,明日要去面個不知名的公司,準備下吧,先把樹狀陣列和trie圖複習下,明天湊合應對。
不多說,上問題:
給你乙個陣列a[n],假設存int數,對這個陣列的操作有2種:(1)修改陣列中某元素的值(2)查詢該陣列任意區間的和。見poj2481.
最樸素想法:在原陣列上操作,對於每個操作(1),修改該位置的值,對於(2)操作,遍歷陣列求和,複雜度為m+q*n(m為修改次數,q為查詢次數,n為陣列size),當n很大時無法忍受。
樹狀陣列解決此問題的複雜度為:(m+q)*log2(n);
原理:查詢某區間[a,b]的和等價於求解sum(b)-sum(a-1)(sum(k)為[1,k]的和);故轉化為求解前k項和的問題了。聯想線段樹分段處理的思想,此處不是二分,而是另一種分段方法。其實可用線段樹解決之,但沒有樹狀陣列處理簡單。開另一陣列c[n],元素c[k]儲存的值為區間[k-lowbit(k]+1,k]的和。lowbit(k)=k表示成二進位制後最右邊的位代表的十進位制數,即k能整除的最大的(2^x);舉個例子:6,表示成2進製為00000110,最右邊的位為第2位,故lowbit=2^(2-1)=2,6能整除的2的次方為2。上經典圖:
c陣列構成乙個樹狀關係:c[x]分布在 log2(lowbit(x)) 層;每個c[k]只有乙個父親節點,子節點與其父節點之間的距離為lowbit(k)。
由圖可知修改和查詢的複雜度都為log2(n);
求lowbit很巧妙:x&(x^(x-1));
x:(k1個0或1)1(k2個0)
x-1:(k1個0或1)0(k2個1)
x^(x-1): (k1個0)1(k2個1)
x&(x^(x-1)) (k1個0)1(k2個0)//即得lowbit(x);
看了下另外乙個自己寫的原始碼:原來還有一種更簡單的lowbit求法:lowbit = x&(-x);
x:(k1個0或1)1(k2個0)
~x:(k1個1或0)0(k2個0)
-x=~x+1: (k1個1或0)1(k2個0)
x&(-x)
(k1個0)1(k2個0)//即得lowbit(x);
類似巧妙的還有:判斷乙個數是否為2的次方if((x&-x)==x);
**如下:
int
lowbit
(int x)//位運算求lowbit(x)
void
add(
int x,int val)//修改位置x的值,val為變化值,可為+-;
}int
getsum
(int x)//求sum(x)
return result;
}
可公升級為2維及多維:
修改2維矩陣某個值,求區間[x1,y1]~[x2,y2]的和。類似,**如下:
int
lowbit
(int x)
void
add(
int x,
int y,
int det)
intgetsum
(int x,
int y)
樹狀陣列複習筆記
樹狀陣列,字首和,差分 首先我們要明白樹狀陣列維護的是字首和,這也是普通樹狀陣列只能區間修改單點查詢或者單點修改區間查詢的原因。其實樹狀陣列也是可以支援區間修改區間查詢的。我們設陣列 t 為陣列 a 的差分陣列,那麼顯然差分陣列的字首和陣列就是原陣列 a 設陣列 sum 為 a 的字首和陣列。那麼就...
演算法 樹狀陣列
演算法適用於求前k個整數的和,一般的做法是設定乙個sum陣列來表示 1 問題公升級一下 在查詢的過程中隨時給第x個整數加上乙個整數v,同樣要求查詢第k個整數的和。此時若還是原來的sum陣列,則要遍歷來更新,複雜度為o n 而用樹狀陣列則時間要更快。2 再來一題 很簡單的,別怕昂 計算序列中在元素左邊...
演算法 樹狀陣列
相信大家都會樹狀陣列的 單點修改,區間查詢 或者 區間修改,單點查詢 博主就不細講了。但是博主今天發現了乙個神奇的演算法 博主太菜 它可以使用樹狀陣列維護 區間修改,區間查詢 就是乙個優化過的字首和,使查詢和修改協調為 theta log 2n namespace fentree void add ...