1
一、一維樹狀陣列
1、單點修改+區間查詢(應用:求逆序對,求區間最大值)
lowbit()函式:求x的補碼(x&-x)
意義:得到的是x的二進位制表示中,最低位的1表示的數
如 5 二進位制表示為101,所以最低位的1所在的位置是0,所以lowbit(5)=2^0=1;
字尾陣列:
sum[1]=a[1];
sum[2]=a[2]+a[1];
sum[3]=a[3];
sum[4]=a[4]+a[3]+a[2]+a[1];
sum[5]=a[5];
即對於字尾和sum[x],表示的是從a[x]開始向前共加lowbit(x)項。
當我們修改某一點a[x]的值時,要將修改的資訊向上傳遞,而且通過加上lowbit(x)可以發現對應的sum中恰好含有a[x]這一項,這樣就可以對所有含有a[x]的sum進行修改。
查詢區間1~x的和時,通過lowbit可以把大的區間劃分成各個不重疊的小區間,然後加起來即可。(把字尾陣列寫出來就可以發現規律)
**:單點修改:
void update(int p,int c)
}
區間查詢:
int query(int x)
return ans;
}
求逆序對
求最大值:
2、區間修改+單點查詢
利用差分序列的思想,此時樹狀陣列的意義與前面不同。
對於陣列a[i],記此時tree[i]=a[i]-a[i-1];(a[0]=0)tree[1]=a[1];
有 a[i]=tree[1]+……+tree[i];
所以當要修改區間(l~r),使每個數都加上c時,只需要令tree[l]+=c,令tree[r+1]-=c;(即使得區間
l~r內的數與前面的數的差值增大,與後面的差值減小),即轉化為對單點的修改,對單點修改可以通過樹狀陣列來實現,再通過求樹狀陣列前x項和就可以得到a[x]的值。
單點修改:
void update(int p,int c)
}
區間修改:
void range_update(int l,int r,int c)
區間查詢:
int query(int p)
return sum;
}
3、區間修改+區間查詢
同樣是基於2中的差分思想。對於2中的差分序列,
當要求前1項和時,用一次tree[1];
求前兩項和時,用二次tree[1],一次tree[2];
以此類推;
當求前p項和時,用p次tree[1],(p-1)次tree[2],……,(p-i+1)次tree[i],所以前p項和為
ans=(p+1) 乘(tree[i]的前p項和)-(i * tree[i]的前p項和);
因此,我們可以通過維護兩個陣列來解決;
tree1[i]=tree[i];
tree2[i]=i*tree[i];
因此要求前p項和時,只需要進行一次查詢即可,求區間(l~r)時,進行兩次查詢,然後相減即可。
進行修改時,對於tree1[i],與 2 中一樣修改。對於tree2[i],在前面的基礎上乘個i即可。同樣轉化為單點修改問題。
單點修改:
void update(int p,int c)
}
區間修改:
void range_update(int l,int r,int c)//區間修改
前p項和查詢:
int query(int p)//求前p項和
return sum;
}
區間查詢:
int query(int l,int r)//區間查詢
二、二維樹狀陣列
1、單點修改+區間查詢
2、區間修改+單點查詢
3、區間修改+區間查詢
樹狀陣列總結
樹狀陣列的基本知識已經被各種大牛和菜鳥講到爛了,我就不多說了,下面給出基本操作的 假定原陣列為a 1.n 樹狀陣列b 1.n 考慮靈活性的需要,使用int a傳陣列。define lowbit x x x int sum int a,int x void update int a,int x,int...
樹狀陣列總結
樹狀陣列是對乙個陣列改變某個元素和求和比較實用的資料結構。兩中操作都是o logn 在解題過程中,我們有時需要維護乙個陣列的字首和s i a 1 a 2 a i 但是不難發現,如果我們修改了任意乙個a i s i s i 1 s n 都會發生變化。可以說,每次修改a i 後,調整字首和s在最壞情況下...
樹狀陣列總結
今天學習了一下樹狀陣列,做乙個簡單總結。樹狀陣列可分為兩種操作,1 修改單個點,統計區間和 一般為 向上修改 update1 向下統計 sum1 2 修改區間,統計單個點 一般為向下修改 update2 向上統計 sum2 主要模板如下 int c n int lowbit int x 用於確定區間...