樹狀陣列
下標記得是從1開始,本節點id透過加lowbit可以訪問到父節點的id,用於點修。
本節點id減去lowbit則是檢視左邊第一個比自己高一級的節點id,比如7會查到6,6會查到4,這樣子累加此三個的值就可以得到前七個的字首和。
int treeArr[M] = {0}; // start from 1
int lowbit(int x) {
return x & (-x);
}
void change(int i, int x){ // add x on ith arrry
while (i < M) {
treeArr[i] += x;
i += lowbit(i);
}
}
int query(int i){
int sum=0;
while(i >= 1) {
sum += treeArr[i];
i -= lowbit(i);
}
return sum;
}
例題(from acwing1267)
NK 中學組織同學們去五雲山寨參加社會實踐活動,按慣例要乘坐火車去。
由於 NK 中學的學生很多,在火車開之前必須清點好人數。
初始時,火車上沒有學生,當同學們開始上火車時,年級主任從第一節車廂出發走到最後一節車廂,每節車廂隨時都有可能有同學上下。
年級主任走到第 m 節車廂時,他想知道前 m 節車廂上一共有多少學生。
他沒有調頭往回走的習慣,也就是說每次當他提問時,m 總會比前一次大。
輸入格式
第一行兩個整數 n,k,表示火車共有 n節車廂以及 k個事件。
接下來有 k行,按時間先後給出 k個事件,每行開頭都有一個字母 A,B或 C。
如果字母為 A,接下來是一個數 m,表示年級主任現在在第 m 節車廂;
如果字母為 B,接下來是兩個數 m,p,表示在第 m 節車廂有 p 名學生上車;
如果字母為 C,接下來是兩個數 m,p,表示在第 m 節車廂有 p 名學生下車。
學生總人數不會超過 10^5。
輸出格式
對於每個事件 A,輸出一行,一個整數,表示年級主任的問題的答案。
#include<iostream>
using namespace std;
const int M = 500003;
// Binary Indexed Trees
int treeArr[M] = {0}; // start from 1
int lowbit(int x) {
return x & (-x);
}
void change(int i, int x){ // add x on ith arrry
while (i < M) {
treeArr[i] += x;
i += lowbit(i);
}
}
int query(int i){
int sum=0;
while(i >= 1) {
sum += treeArr[i];
i -= lowbit(i);
}
return sum;
}
int main(){
int n,k;
cin>>n>>k;
for (int i=0; i<k; i++) {
char c;
int a, b;
cin>>c;
if (c == 'A') {
cin>>a;
cout<<query(a)<<endl;
} else if (c =='B') {
cin>>a>>b;
change(a, b);
} else {
cin>>a>>b;
change(a, -b);
}
}
return 0;
}