更新
图床烂了,没备份,只能阴间再见了 2024-06-24
二维前缀和
我们先对用到的一些概念进行符号定义。
符号约定
我们用:
A=(aij)=a1,1a2,1⋮am,1a1,2a2,2⋮am,2⋯⋯⋱⋯a1,na2,n⋮am,nm×n
表示一个 m 行 n 列的矩阵。其中,对于 ∀i,j∈N 且 1⩽i⩽m,1⩽j⩽n 有 ai,j∈Z.
我们用:
Ar1:r2, c1:c2=ar1, c1ar1+1, c1⋮ar2, c1ar1, c1+1ar1+1, c1+1⋮ar2, c1+1⋯⋯⋱⋯ar1, c2ar1+1, c2⋮ar2, c2(r2−r1+1)×(c2−c1+1)
表示矩阵 A 的一个子块,其中 r1,r2,c1,c2∈N 且 1⩽r1⩽r2⩽m 以及 1⩽c1⩽c2⩽n.
我们定义集合:
Mm×n(Z)={A ∣ ∀i,j∈N∧1⩽i⩽m∧1⩽j⩽n, ai,j∈Z}
用函数:
Sum:M(r2−r1+1)×(c2−c1+1)(Z)→ZSum(Ar1:r2, c1:c2)=i=r1∑r2j=c1∑c2ai,j
表示一个子块的元素之和。
定义函数:
AddSubMat:Mm×n(Z)×N2×N2×Z→Mm×n(Z)AddSubMat(A,r1,c1,r2,c2,x)=C
其中 1⩽r1⩽r2⩽m,1⩽c1⩽c2⩽n,x∈Z 且:
C=(cij)m×n={aij+xaij,if i∈[r1,r2]∧j∈[c1,c2],else
表示对矩阵一个子块里的所有元素加 x 的操作。
定义函数:
AddMatCell:Mm×n(Z)×N2×Z→Mm×n(Z)AddMatCell(A,r,c,x)=F
其中 1⩽r⩽m,1⩽c⩽n,x∈Z 且:
F=(fij)m×nfij={aij+xaij,if i=r∧j=c,else
表示对矩阵某个位置上的元素加 x 的操作。
功能预告
二维前缀和在花费 O(n2) 的时间进行预处理之后, 能以 O(1) 的复杂度回答 Sum(Ar1:r2, c1:c2).
具体做法
我们首先定义前缀和函数:
PreSum:Mm×n×N×N→ZPreSum(A,r,c)=i=1∑rj=1∑caij
定义矩阵 A 的前缀和矩阵:
SA=(sij)=(PreSum(A,i,j))=∑i=11∑j=11aij∑i=12∑j=11aij⋮∑i=1m∑j=11aij∑i=11∑j=12aij∑i=12∑j=12aij⋮∑i=1m∑j=12aij⋯⋯⋱⋯∑i=11∑j=1naij∑i=12∑j=1naij⋮∑i=1m∑j=1naijm×n
形象地,前缀和矩阵 Sij 等于原矩阵 Aij 左上部分的所有元素之和。即如下图一所示的深橙色部分。
现在考虑如何根据原矩阵计算出前缀和矩阵。我们将 Src 划分:
Src=i=1∑rj=1∑caij=Part 1i=1∑r−1j=1∑c−1aij+Part 2i=1∑r−1aic+Part 3j=1∑c−1arj+arc
形象地,如下图二所示:
Part 1 对应黄色部分,Part 2 对应蓝色部分,Part 3 对应绿色部分,arc 对应橙色部分。
观察矩形面积,直观地有(马上仔细证):
SOQYV=SOQUR+SOPWV−SOPTR+STUYW(1)
注意到黄色部分加上蓝色部分即为 Sr−1,c 类似地,黄色部分加上绿色部分即为 Sr,c−1. 于是考虑多添加一项 Part 1 再减去 Part 1:
Src=i=1∑r−1j=1∑c−1aij+i=1∑r−1aic+j=1∑c−1arj+arc=(i=1∑r−1j=1∑c−1aij+i=1∑r−1aic)+(i=1∑r−1j=1∑c−1aij+j=1∑c−1arj)−i=1∑r−1j=1∑c−1aij+arc=i=1∑r−1j=1∑caij+i=1∑rj=1∑c−1aij−i=1∑r−1j=1∑c−1aij+arc=Sr−1,c+Sr,c−1−Sr−1,c−1+arc(2)
观察 (2) 式,只需要求出 Sr−1,c 和 Sr,c−1 和 Sr−1,c−1 我们就可以立即得到 Sr,c. 显然这些项的下标都在 r 和 c 之前,于是可以使用递推预处理:
| for (int i = 1; i <= m; i++) { for (int j = 1; j <= n; j++) { s[i][j] = s[i - 1][j] + s[i][j - 1] - s[i - 1][j + 1] + a[i][j]; } }
|
预处理结束之后,我们考虑如何利用前缀和 S 回答查询 Sum(Ar1:r2, c1:c2). 回想到我们刚刚递推预处理出 S 的递推公式:
Src=Sr−1,c+Sr,c−1−Sr−1,c−1+arc
显然我们可以对这一式子进行推广,把 arc 替换为子块和 Sum(Ar1:r2, c1:c2),即:
Sr2,c2=Sr1−1,c2+Sr2,c1−1−Sr1−1,c1−1+Sum(Ar1:r2, c1:c2)(3)
如下图,图三把图二的橙色部分替换成紫色区块,类似式 (1) 的面积等式依然成立。严格的数学证明过程与 (2) 式的推导类似,不再赘述。
对式 (3) 进行移项,由于前缀和矩阵我们已经预处理计算完成,我们便能够在常数时间内回答询问 Sum(Ar1:r2, c1:c2):
Sum(Ar1:r2, c1:c2)=Sr2,c2−Sr1−1,c2−Sr2,c1−1+Sr1−1,c1−1
二维差分
功能预告
二维差分能在常数时间内维护 AddSubMat 操作,在所有操作完成之后,以 O(n2) 的时间复原出原矩阵。
具体做法
我们定义矩阵 A 的差分矩阵为 D 当且仅当:
A=SD
即:
(aij)=(PreSum(D,i,j))
即矩阵 A 是 D 的前缀和矩阵。
根据定义和式 2,我们可以立即得到:
Ar,c=Ar−1,c+Ar,c−1−Ar−1,c−1+Dr,c
移项得到差分矩阵 D 的计算公式:
Dr,c=Ar,c−Ar−1,c−Ar,c−1+Ar−1,c−1(4)
到目前为止,我们只是对差分矩阵进行了定义和计算,但我们还不能看出它有什么具体的作用。接下来,我们将发掘它的良好性质,再看看怎样把好的性质用于高效维护 AddSubMat 操作。
现在假设我们手中有一个矩阵 A 并根据式 (4) 求出了它的差分矩阵 D. 现在,对 D 的 (r0,c0) 位置进行单点加 x 的操作,即令 D′=AddMatCell(D,r0,c0). 我们有:
Dij′={Dij+xDij,if i=r0∧j=c0,else
我们现在考察新的 D′ 是哪一个矩阵 A′ 的差分矩阵。根据定义,我们有 A′=SD′,现在分类计算 A′ 的每一元素 Arc′ 的值:
1° 当 r∈[r0,m]∧c∈[c0,n] 时:
Arc′=PreSum(D′,r,c)=i=1∑rj=1∑cDij′=1⩽i⩽r,1⩽j⩽ci=r0∧j=c0∑Dij′+Dr0,c0′=1⩽i⩽r,1⩽j⩽ci=r0∧j=c0∑Dij+Dr0,c0+x=x+i=1∑rj=1∑cDij=PreSum(D,r,c)+x=Arc+x
即对于处在 r0 行 c0 列的右下部分所有位置来说,A′ 的值比 A 增加了 x.
2° 当 r∈/[r0,m]∨c∈/[c0,n] 时:
Arc′=PreSum(D′,r,c)=i=1∑rj=1∑cDij′=i=1∑rj=1∑cDij=PreSum(D,r,c)=Arc
即除了 1° 的情况以外,不处在 r0 行 c0 列的右下部分所有位置上 A′ 的值和 A 相等。
综合两种情况,有:
Aij′={Aij+xAij,if r0⩽i⩽m∧c0⩽j⩽n,else(5)
下面给出一个 D4×5=A4×5=0,r0=1,c0=4,x=1 的直观例子:
我们可以发现,AddMatCell(D,r,c) 等价于 AddSubMat(A,r,c,m,n). 即对于差分矩阵的单点加操作等价于对原矩阵的右下块整片加操作。
那么反过来,AddSubMat(A,r,c,m,n) 也等价于 AddMatCell(D,r,c),所以,对原矩阵的右下块整片加操作可以被转化成在差分矩阵的单点加操作。试想,如果我们没有差分矩阵这一工具,要想对右下整片都加上 x,我们只能枚举右下块里的每一个位置,然后对每个位置单点加 x,但现在我们只需要在差分矩阵里对一个位置的值加 x,把时间复杂度从 O(n2) 降到了 O(1). 最后当所有的操作全部完成,只需要对差分矩阵做一次前缀和,即可恢复出原矩阵。
然而,目前我们只能对右下块的整体加操作进行转化,如何扩展才能转化任意一个子块呢?
我们考虑怎样用多个右下块组合表示一个子块。观察下图五:
我们把正准备进行 AddMatCell 的目标子块在图中表示为 OACB. 我们约定 DR(P) 表示以 P 点为左上角的右下块。考虑 DR(O),DR(A),DR(B),DR(C) 和 OACB 的关系。类似之前推导前缀和时用到的面积公式 (1),我们有:
SOACB=SDR(O)−SDR(A)−SDR(B)+SDR(C)
于是我们用四个右下块组合表示了一个子块,即对于子块 OACB 的整体加 x 操作,可以转化成:
- 对于 DR(O) 的整体加 x 操作
- 对于 DR(A) 的整体减 x 操作
- 对于 DR(B) 的整体减 x 操作
- 对于 DR(C) 的整体加 x 操作
这四个操作的结合。然后,我们利用对原矩阵右下块整体加操作等价于差分矩阵的单点加操作这一优良性质,再把这四个操作转化成 O(1) 的单点加操作。
具体地,对于操作 AddSubMat(A,r1,c1,r2,c2,x),我们转化为:
- AddMatCell(D,r1,c1,x)
- AddMatCell(D,r1,c2+1,−x)
- AddMatCell(D,r2+1,c1,−x)
- AddMatCell(D,r2+1,c2+1,x)
如下图六所示:
我们可以对差分矩阵进行前缀和,检验这样的转化是否正确:
1° 当 r1⩽r⩽r2∧c1⩽c⩽c2 时,由于 Dr1,c1 被加上了 x,所以 Ar,c 都被加上了 x,如下图七;
2° 当 r1⩽r⩽r2∧c>c2 时,由于 Dr1,c1 被加上了 x,Dr1,c2+1 被减去了 x,所以两者抵消,Ar,c 不变,如下图八;
3° 当 r>r2∧c1⩽c⩽c2 时,由于 Dr1,c1 被加上了 x,Dr2+1,c1 被减去了 x,所以两者抵消,Ar,c 不变,如下图九;
3° 当 r>r2∧c>c2 时,四个操作点都被覆盖,相互抵消,所以 Ar,c 不变,如下图十;
严格的数学证明类似式 (5) 的推导,这里不再赘述。