原文链接设原数组第ii位的值为aiai,di=ai−ai−1di=ai−ai−1,则有(这里认为a0=0a0=0):
ax=∑i=1xdiax=∑i=1xdi
所以有:
∑i=1xai=∑i=1x∑j=1idj=∑i=1x(x−i+1)di∑i=1xai=∑i=1x∑j=1idj=∑i=1x(x−i+1)di
于是我们得到了:
∑i=1xai=(x+1)∑i=1xdi−∑i=1xdi×i∑i=1xai=(x+1)∑i=1xdi−∑i=1xdi×i
于是我们把原数组差分后维护两个树状数组,一个维护 didi,一个维护 di×idi×i。
这样区间求和时可以在两个树状数组中查询得到前缀和,区间修改时就是差分数组的修改,每次修改两个点即可。
具体代码如下:
void add(int x,int y){for(int i=x;i<=n;i+=i&(-i)) c1[i]+=y,c2[i]+=(long long)x*y;}//给差分数组中的位置x加上y
long long sum(int x){//查询前x项的和
long long ans(0);
for(int i=x;i;i-=i&(-i)) ans+=(x+1)*c1[i]-c2[i];
return ans;
}
其中c1ic1i维护的是didi,c2ic2i维护的是di×idi×i。