【c++】淺析樹狀數組

驚喜累加器

目錄

單點修改+區間查詢

代碼

區間修改 + 單點查詢

修改

查詢

代碼

區間修改 + 區間查詢

查詢

代碼


單點修改+區間查詢

單點修改仍是模板,區間查詢[x,y]時,我們利用前綴和的思想,即(sum[y] - sum[x - 1])即可算出答案

代碼

#include<cstdio>
#define M 500000
#define low_bit(x) (x & -x)
#define reg register

inline void read(int &x){
    x = 0;
    int f = 1;
    char s = getchar();
    while (s < '0' || s > '9'){
        if (s == '-')
            f = -1;
        s = getchar();
    }
    while (s >= '0' && s <= '9'){
        x = x * 10 + s - '0';
        s = getchar();
    }
    x *= f;
}

int C[M + 5];
int n,m;

void Add(int x,int y){
    for (reg int i = x;i <= n;i += low_bit(i))
        C[i] += y;
    return ;
}

int Query(int x){
    int sum = 0;
    for (reg int i = x;i;i -= low_bit(i))
        sum += C[i];
    return sum;
}

int main(){
    read(n),read(m);
    for (reg int i = 1;i <= n; ++ i){
        int a;
        read(a);
        Add(i,a);
    }
    for (reg int i = 1;i <= m; ++ i){
        int a,b,c;
        read(a),read(b),read(c);
        if (a == 1)
            Add(b,c);
        else printf("%d\n",Query(c) - Query(b - 1));
    }
    return 0;
}

區間修改 + 單點查詢

修改

這裏引入差分的思想。

設原數組爲A,則差分數組B[i] = A[i] - A[i - 1]

這道題跟差分有什麼關係呢?(方便解題呀)

設A[6] = {0,1,2,3,4,5}

則B[6] = {0,1,1,1,1,1}

接着在 2 - 4 區間裏每個數加一,則

A[6] = {0,1,3,4,5,5}

B[6] = {0,1,2,1,1,0}

由此,我們可看出 B 數組中,B[2] + 1,B[5] - 1

查詢

以上面的例子爲例,求A[3]的值(顯然爲4)

我們進行分析:A[3] = A[3] - A[2] + A[2] - A[1] + A[1] - A[0] = B[3] + B[2] + B[1] = A[3] - A[0] = 4

顯然就是求B數組的和

代碼

#include<cstdio>
#define M 500000
#define low_bit(x) (x & -x)
#define reg register

inline void read(int &x){
    x = 0;
    int f = 1;
    char s = getchar();
    while (s < '0' || s > '9'){
        if (s == '-')
            f = -1;
        s = getchar();
    }
    while (s >= '0' && s <= '9'){
        x = x * 10 + s - '0';
        s = getchar();
    }
    x *= f;
}

int B[M + 5],A[M + 5];
int n,m;

void Add(int x,int y){
    for (reg int i = x;i <= n;i += low_bit(i))
        B[i] += y;
    return ;
}

int Query(int x){
    int sum = 0;
    for (reg int i = x;i;i -= low_bit(i))
        sum += B[i];
    return sum;
}

int main(){
    read(n),read(m);
    for (reg int i = 1;i <= n; ++ i){
        read(A[i]);
        Add(i,A[i] - A[i - 1]);
    }
    for (reg int i = 1;i <= m; ++ i){
        int a;
        read(a);
        if (a == 1){
            int x,y,k;
            read(x),read(y),read(k);
            Add(x,k);
            Add(y + 1,-k);
        }
        else {
            int x;
            read(x);
            printf("%d\n",Query(x));
        }
    }
    return 0;
}

區間修改 + 區間查詢

顯然修改是不會變的,變的是查詢

查詢

A[1] + A[2] + A[3] + …+ A[N - 1] + A[N] = B[1] + B[1] + B[2] + B[1] + B[2] + B[3] + … + B[N - 1] + B[N]

                                                               = N * B[1] + (N - 1) * B[2] + … + B[N]

                                                               =  N * (B[1] + B[2] + … + B[N]) - (0 * B[1] + 1 * B[2] + … + (N - 1) * B[N])

因而,我們可以在B數組的基礎上再用一個B2數組,令 B2[i] = (i - 1) * (A[i] - A[i - 1])

這樣就能很方便的求出答案了。

注: 如果給出區間的左端點 x,不是從一開始的,那麼我們可以借鑑 單點修改+區間查詢 的前綴和思想(具體操作見代碼)

代碼

#include<cstdio>
#define lowbit(x) (x & -x)
#define M 100000
#define LL long long
#define reg register

inline void read(int &x){
    x = 0;
    int f = 1;
    char s = getchar();
    while(s < '0' || s > '9'){
        if (s == '-')
            f = -1;
        s = getchar();
    }
    while (s >= '0' && s <= '9'){
        x = x * 10 + s - '0';
        s = getchar();
    }
    x *= f;
}

int n,m;
LL C[M + 5],C2[M + 5];
int A[M + 5];

void update(int x,LL k){
    for (reg int i = x;i <= n;i += lowbit(i)){
        C[i] += k;
        C2[i] += (x - 1) * k;
    }
    return ;
}
LL  query(int x){
    LL sum1 = 0,sum2 = 0;
    for (reg int i = x;i;i -= lowbit(i)){
        sum1 += C[i];
        sum2 += C2[i];
    }
    return sum1 * x - sum2;
}
inline LL Su(int x,int y){
    LL sum =  query(y);
    sum -= query(x - 1);
    return sum;
}

int main(){
    read(n),read(m);
    for (reg int i = 1;i <= n; ++ i){
        read(A[i]);
        update(i,A[i] - A[i - 1]);
    }
    for (reg int i = 1;i <= m; ++ i){
        int pd;
        read(pd);
        if (pd == 1){
            int x,y,k;
            read(x),read(y),read(k);
            update(x,k);
            update(y + 1,-k);
        } else {
            int x,y;
            read(x),read(y);
            printf("%lld\n",Su(x,y));
        }
    }
    return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章