先说下对树状数组主要部分的理解:
lowbit  x&(-x) 依照补码的特性,取反后第一位(低到高)原本是1的数 会变成一其他取反,也就导致了返回最高的低位连续0位置
区间查询 以区间和的形式来理解
int query(int x){
    int ans=0;
    while(x>0){
        ans+=sum[x];
        x-=lowbit(x);
    }
    return ans;
}
x-lowbit(x)意味着x的二进制位从低到高把1变为0 直到全部为0;因为sum[i]=a[i-2^k+1]……a[i]  也就是sum[i]可以表示出从i----i-lowbit(i) +1这个范围的和 一次查找就得到了i--0的区间和时间复杂度显然是O(log(n))
区间更新:
void add(int i,int va){
    while(i<=n){
        sum[i]+=va;
        i+=lowbit(i);
    }
}
在这们的目的是 把包含a[i]的sum[x] 都更新一边 ,也就是我们要通过i去找x,从上面我们可以知道x包含的范围是前连续0最高位 由1变0+最低位+1  的范围
所以找出最低位的1看做是小的范围一次向上去查找就是包含它的sum[i](相当于遍历了所有处于这两个数范围的值)
上一道模板题 (跟线段树的模板题一样,可以对比学习):http://acm.hdu.edu.cn/showproblem.php?pid=1166

#include<bits/stdc++.h>
using namespace std;
long long  sum[50004];
int  n;
int lowbit(int x){
    return x&(-x);
}
int query(int x){
    int ans=0;
    while(x>0){
        ans+=sum[x];
        x-=lowbit(x);
    }
    return ans;
}
void add(int i,int va){
    while(i<=n){
        sum[i]+=va;
        i+=lowbit(i);
    }
}
int main(){
//    freopen("1.txt","r",stdin);
    int t;
    cin>>t;
    for(int j=1;j<=t;j++){
        cout<<"Case "<<j<<":"<<endl;
        cin>>n;
        memset(sum,0,sizeof(sum));
        for(int i=1;i<=n;i++){
            int x;
            cin>>x;
            add(i,x);
        }
        char s[10];
        while(cin>>s&&s[0]!='E'){
            int x,y;
            cin>>x>>y;
            if(s[0]=='Q') cout<<query(y)-query(x-1)<<endl;
            if(s[0]=='A') add(x,y);
            if(s[0]=='S') add(x,-y);
        }
    }
}