树状数组的思想原理:前缀和加上类似倍增的思想,相当于前缀和的进阶版
树状数组的序号必须从1开始。
实现原理
每个元素用二进制表示,最右侧的‘1’是储存的区间和的区间长度
lowbit:i&(-i)就是求i的最右边的‘1’
每个元素x储存的区间:[x-lowbit[x]+1,x](理解为:【当前位置-区间长度+1,当前位置】。比如12,储存的就是[9,12]的区间和)
基本应用
正常树状数组:范围查询,单点修改
差分树状数组:范围修改,单点查询
应用实现与原理
前缀和查询(范围[1,i],返回ans):
(i对应的树状数组元素所储存的区间是[i-lowbit[i]+1,i])
1.ans加上i对应的树状数组元素(就是[i-lowbit[i]+1,i]的区间和)
2.i减去lowbit(i)。由于已经算出[i-lowbit[i]+1,i]的区间和,所以将区间缩小到[0,i-lowbit(i)]。如果i==0,说明已经算完了。
代码
int sum(int i){
int ans = 0;
while(i>0){
ans+=tree[i];
i-=lowbit(i);
}
return ans;
}
区间和查询(范围[l,r])
代码
int query(int l,int r){
return sum(r)-sum(l-1);
}
单点修改(位置i,加上k)
目标就是找到哪些树状数组元素包含这个位置i。
而i+lowbit(i)一定包含i。
代码
void add(int i,int k){
while(i<=n){
tree[i]+=k;
i+=lowbit(i);
}
}