树状数组
就差不多这个样子的:
在这里插入图片描述
c [ i ] = a [ i − 2 k + 1 ] + a [ i − 2 k + 2 ] + . . . + a [ i ] c[i]=a[i-2^k+1]+a[i-2^k+2]+...+a[i] c[i]=a[i−2k+1]+a[i−2k+2]+...+a[i]
lowbit
lowbit操作是求出非负整数x的最后一位1所表示的数值。
int lowbit(int t) {return t&(-t);}
修改:
void update(int x,int y){
for(int i=x;i<=n;i+=lowbit(i))
c[i]+=y;
}
查询:
int getsum(int x){
int ans=0;
for(int i=x;i;i-=lowbit(i))
ans+=c[i];
return ans;
}
例题
1.单点修改,区间查询
修改:
void update(int x,int y){
for(int i=x;i<=n;i+=lowbit(i))
c[i]+=y;
}
查询:
int getsum(int L,int R){//运用前缀和
int ans = 0;
for(int i=L-1;i;i-=lowbit(i))
ans-=c[i];
for(int i=R;i;i-=lowbit(i))
ans+=c[i];
return 0;
}
2.区间修改,单点查询
修改:
void update(int x,int y){
for(int i=x;i<=n;i+=lowbit(i))
c[i]+=y;
}
update(L,k);
update(R+1,-k);//这里使用了差分
查询:
int getsum(int x){
int ans=0;
for(int i=x;i;i-=lowbit(i))
ans+=c[i];
return ans;
}
3.区间修改,区间查询
依旧使用差分,再求前缀和的前缀和
例题:
BIT-3:
题目描述
给定数组 a_1,a_2…a_n,进行 q 次操作,操作有两种:1 l r k:将 a_i~a_k 每个数都加上 k;
2 l r:求 a_l+a_{l+1}…+a_r
输入格式
第一行:输入两个数 n,q,表示给定数组的长度和操作数
第二行:输入 n 个数,表示长度为 n 的给定数组
接下来 q 行:每行输入表示如题的某一种操作
输出格式
对于每个 2 操作,输出对应结果
解题思路:
这个题是区间修改,区间查询
可以考虑之前的区间修改,单点查询
单点查询是求差分数组前缀,得到某个点的值a[x]
如果再求一次前缀,就是我们想要的答案sum[x]
在等号右侧的式子中,d[1]用了p次,d[2]用了p-1次…
所以,维护两个前缀和数组
sum1 维护 d 数组的前缀和
sum2 维护 d*i 的前缀和
区间查询
位置 p 的前缀和即: (p + 1) * sum1 数组中 p 的前缀和 - sum2 数组中 p 的前缀和。区间[l, r]的和即:位置 r 的前缀和 - 位置 l 的前缀和。