树状数组 1 :单点修改与区间查询

Description
给定数列
a[1],a[2],…,a[n],你需要依次进行 q个操作,操作有两类:
1 i x:给定 i,x将 a[i]加上 x;
2 l r:给定 l,r,求a[l]+a[l+1]+…+a[r] 的值)。
Input
第一行包含 2 个正整数 n,q,表示数列长度和询问个数。保证 1≤n,q≤10^6 。
第二行 n 个整数a[1],a[2],…,a[n],表示初始数列。保证 ∣a[i]∣≤10^6
接下来 q 行,每行一个操作,为以下两种之一:
1 i x:给定 i,x,将 a[i] 加上 x;
2 l r:给定 l,r,
保证 1≤l≤r≤n∣x∣≤10^6
Output
对于每个 2 l r 操作输出一行,每行有一个整数,表示所求的结果。
Sample Input

3 2
1 2 3
1 2 0
2 1 3

Sample Output

6

以上就是单点修改与区间查询的模板题目

树状数组的单点修改与区间查询,树状数组的入门,这个就是一个模板,由于本人刚接触这方面,对LowBit(x&-x)的用法不是很清楚(只是知道他是干嘛的),本文就以正常的写法实现,对下面用一道入门题目验证代码的正确性。(切记将结构体数组开为上限的四倍,原因就是因为是树结构嘛,各位大犇应该都知道!!!

传送门

#include
using namespace std;
const int maxn=5e4+5;
int a[maxn];
int sum;
struct node{
    int l,r,ans;
}t[maxn<<2];
inline void build(int l,int r,int index){
    t[index].l=l;
    t[index].r=r;
    if(l==r){
        t[index].ans=a[r];
    }
    else{
        int mid=(l+r)>>1;
        build(l,mid,index<<1);
        build(mid+1,r,(index<<1)|1);
        t[index].ans=t[(index<<1)|1].ans+t[index<<1].ans;
    }
}
inline void query(int l,int r,int index){
    if(t[index].l>=l&&t[index].r<=r){
        sum+=t[index].ans;
    }
    else{
        int mid=(t[index].r+t[index].l)>>1;
        if(l>=mid+1){
            query(l,r,(index<<1)|1);
        }
        else if(r<=mid){
            query(l,r,index<<1);
        }
        else{
            query(l,r,index<<1);
            query(l,r,(index<<1)|1);
        }
    }
}
inline void add(int x,int y,int index){
    t[index].ans+=y;
    if(t[index].l==t[index].r){
        return ;
    }
    int mid=(t[index].l+t[index].r)>>1;
    if(x>mid){
        add(x,y,(index<<1)|1);
    }
    else if(x<=mid){
        add(x,y,index<<1);
    }
}
inline void sub(int x,int y,int index){
    t[index].ans-=y;
    if(t[index].l==t[index].r){
        return ;
    }
    int mid=(t[index].l+t[index].r)>>1;
    if(x>mid){
        sub(x,y,(index<<1)|1);
    }
    else if(x<=mid){
        sub(x,y,index<<1);
    }
}
int main(){
    int T,num=0;
    char command[10];
    int x,y,n;
    scanf("%d",&T);
    while(T--){
        scanf("%d",&n);
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
        }
        build(1,n,1);
        printf("Case %d:\n",++num);
        while(1){
            
            scanf("%s",command);
            if(command[0]=='E'){
                break;
            }
            else if(command[0]=='Q'){
                sum=0;
                scanf("%d%d",&x,&y);
                query(x,y,1);
                printf("%d\n",sum);
            }
            else if(command[0]=='S'){
                scanf("%d%d",&x,&y);
                sub(x,y,1);
            }
            else if(command[0]=='A'){
                scanf("%d%d",&x,&y);
                add(x,y,1);
            }
        }

    }
    return 0;
}

你可能感兴趣的:(树状数组 1 :单点修改与区间查询)