树状数组的两种运用

运用1

单点修改,区间查询。

add(pos,x)->在下标 pos 处加上 x
query(pos)->返回 1 到 pos 的前缀和

那么查询区间 [ l , r ]的操作就是query( r ) - query( l - 1 )

例题——洛谷3374

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<cmath>
using namespace std;
const int maxn=500000+10;
int a[maxn];
int n,m;
inline int lowbit(int x){
    return x&(-x);
}
inline void add(int pos,int val){
    while(pos<=n){
        a[pos]+=val;
        pos+=lowbit(pos);
    }
}
inline int query(int pos){
    int res=0;
    while(pos>0){
        res+=a[pos];
        pos-=lowbit(pos);
    }
    return res;
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++){
        int x;
        scanf("%d",&x);
        add(i,x);//赋初值 
    }
    for(int i=1;i<=m;i++){
        int op;
        scanf("%d",&op);
        if(op==1){
            int x,y;
            scanf("%d%d",&x,&y);
            add(x,y);
        }
        if(op==2){
            int x,y;
            scanf("%d%d",&x,&y);
            printf("%d
",query(y)-query(x-1));
        }
    }
    return 0;
}

运用二

区间修改,单点查询

add 和 query 的操作同运用一,但是使用方式不同:
区间修改(给区间 [ l , r ]加上 d)->

add(l,d);
add(r+1,-d);

单点查询(查询 pos 的值)->

query(pos);

例题——洛谷3368

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<cmath>
using namespace std;
const int maxn=500000+10;
int c[maxn]; 
int n;
inline int lowbit(int x){
    return x&(-x);
}
inline void add(int pos,int val){
    while(pos<=n){
        c[pos]+=val;
        pos+=lowbit(pos);
    }
}
inline int query(int pos){
    int res=0;
    while(pos>0){
        res+=c[pos];
        pos-=lowbit(pos);
    }
    return res;
}
int main(){
    int m;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++){
        int x;
        scanf("%d",&x);
        add(i,x);
        add(i+1,-x);
    }
    for(int i=1;i<=m;i++){
        int op;
        scanf("%d",&op);
        if(op==1){
            int x,y,z;
            scanf("%d%d%d",&x,&y,&z);
            add(x,z);
            add(y+1,-z);
        }
        if(op==2){
            int x;
            scanf("%d",&x);
            printf("%d
",query(x));
        }
    }
    return 0;
}

后记

  1. 两种运用的add 和 query 完全一样。
  2. 至于为什么,感觉不好解释,大概是差分的思想,现场手推一下即可。

挖个坑

据说还有一种区间修改区间查询的,过会儿再写。

原文地址:https://www.cnblogs.com/yohanlong/p/6058147.html