樹狀陣列入門

石中火本火發表於2024-04-21

樹狀陣列

image
下標記得是從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;
}

相關文章