树状数组区间修改 一维&二维差分

· · 个人记录

树状数组的区间修改

差分数组 c[i]=a[i]-a[i-1],则有 a[i]=c[1]+c[2]+...+c[i]

因此,a[1]+a[2]+...+a[x]

=c[1]+c[1]+c[2]+...+c[1]+c[2]+...c[x] =x*c[1]+(x-1)*c[2]+...+c[x] =\sum_{i=1}^{x}(x-i+1)*c[i]

运用数学思想,将变量和常量拆开得:

=\sum_{i=1}^{x}(x+1)*c[i]-\sum_{i=1}^{x}i*c[i]

不妨设 A=\sum_{i=1}^{x}c[i]B=\sum_{i=1}^{x}i*c[i],则:

=(x+1)*A-B

我们只需用树状数组维护 AB 即可。

二维差分

通过定义理解二维差分较难,不妨画图看看。

首先我们知道,给 c[i][j]+k,则等同于将左上角为 (i,j)、右下角为 (n,m) 的矩阵的每个数 +k

那么,考虑给左上角为 (x1,y1)、右下角为 (x2,y2) 的矩阵 +k,如何操作?

  1. c[x1][y1]+k
  2. c[x1][y2+1]-k
  3. c[x2+1][y1]-k
  4. c[x2+1][y2+1]+k

可画图理解。简单地说,就是先加(第一步);加了发现有的不该加就减去(二三步);由于减了两次,所以还要加回去(第四步)。

至于初始化,有一种巧妙做法:初始化数组为 0,在 i,j 加入 k ,等同于将左上角为 (i,j)、右下角为 (i,j) 的矩阵加 k,很好写。

二维区间修改

结合上述两种思想。

\sum_{i=1}^{x}\sum_{j=1}^{y}a[i][j] =\sum_{i=1}^{x}\sum_{j=1}^{y}\sum_{k=1}^{i}\sum_{h=1}^{j}c[i][j]

建议画图看看,c[i][j] 被多少个 a[i][j] 使用?每个 c[i][j] 被用了(x-i+1)(y-j+1) 次。

然后把 ij 单独拎出来。

=\sum_{i=1}^{x}\sum_{j=1}^{y}((x+1)*(y+1)*c[i][j]-(y+1)*c[i][j]*i-(x+1)*c[i][j]*j+c[i][j]*i*j)

像一维一样,设四个树状数组维护即可。