树状数组 区间修改
利用单点修改我们可以做到
1.单点加, 询问区间和
2.区间加, 询问单点值
下面是关于树状数组的区间修改, 询问区间和
假设:
ai
是储存原数据的数组
令:
xi=ai−ai−1 (a0=0)
那么:
xn+xn−1+⋯+x1=(an−an−1)+(an−1−an−2)+⋯+(a1−a0)
右边消去得到:
an=xn+xn−1+⋯+x1
即:
an=∑i=1nxn
那么:
a1+a2+⋯+an=(x1)+(x1+x2)+⋯+(x1+x2+⋯+xn)=n(x1+x2+⋯+xn)−(0⋅x1+1⋅x2+⋯+(n−1)⋅xn)
在区间
l
到
相当于在
xl
位置
+val
, 在
xr+1
位置
−val
又转换成了树状数组单点修改问题
用树状数组分别维护
xi
与
(i−1)⋅xi
这
2
个序列的前缀和
假设:
dn=0⋅x1+1⋅x2+⋯+(n−1)⋅xn
区间更新/询问区间和代码:
int n,c[100005],d[100005];
void update(int l,int r,int val)
{
for(int i=l--; i<=n; i+=i&(-i))
c[i]+=val,d[i]+=l*val;
for(int i=r+1; i<=n; i+=i&(-i))
c[i]-=val,d[i]-=r*val;
}
int get_sum(int l,int r)
{
int res=0;
for(int i=r; i; i-=i&(-i))
res+=r*c[i]-d[i];
for(int i=--l; i; i-=i&(-i))
res-=l*c[i]-d[i];
return res;
}