先说下对树状数组主要部分的理解:
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);
}
}
} 
京公网安备 11010502036488号