树状数组和线段树很像,同样也是解决区间的问题
图解
0001 C1 = A1
0010 C2 = A1 + A2
0011 C3 = A3
0100 C4 = A1 + A2 + A3 + A4
0101 C5 = A5
0110 C6 = A5 + A6
0111 C7 = A7
1000 C8 = A1 + A2 + A3 + A4 + A5 + A6 + A7 + A8
要求Cn,记下标n的二进制末位0的个数为k,可看出,它的管辖区间为2的k次方。
模版
int lowbit(int x){//利用补码的特性算出二进制末位0的个数
return x&(-x);
}
void update(int x,int v){//从低到高更新节点值
while(x<=n){
tree[x]+=v;
x+=lowbit(x);//跳出下标x的管辖范围
}
}
int getsum(int x){//从高到低获取前n项和
int sum=0;
while(x>0){
sum+=tree[x];
x-=lowbit(x);
}
return sum;
}
应用
题源 hdu 1166
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 5;
int tree[maxn];
int N;
//hdu 1166
int lowbit(int x){
return x&(-x);
}
void update(int x,int v){
while(x<=N){
tree[x]+=v;
x+=lowbit(x);
}
}
int getsum(int x){
int sum=0;
while(x>0){
sum+=tree[x];
x-=lowbit(x);
}
return sum;
}
int main(){
int T;
char cmd[10];
scanf("%d",&T);
for(int i=1;i<=T;i++){
scanf("%d",&N);
for(int j=1;j<=N;j++){
int v;
scanf("%d",&v);
update(j,v);
}
printf("Case %d:\n",i);
while(~scanf("%s",cmd)&&strcmp(cmd,"End")){
int x,y;
scanf("%d%d",&x,&y);
if(strcmp(cmd,"Query")==0){
int ans=getsum(y)-getsum(x-1);
cout<<ans<<endl;
}
else if(strcmp(cmd,"Add")==0){
update(x,y);
}
else if(strcmp(cmd,"Sub")==0){
update(x,-y);
}
}
}
return 0;
}