注意
本文章仅仅适合复习使用,本人没有太多时间维护,对于初学者,我很推荐这篇文章 https://www.cnblogs.com/nhwite/p/18996276

变量

功能描述

变量名

说明

原始数组

a

存储原始输入数据

前缀和数组

prefix

prefix[i] = a[1] + ... + a[i]

差分数组

diff

diff[i] = a[i] - a[i-1]

假设 $a$ 的容量为 $n$

前缀和

一维前缀和

$$\text{prefix}[i] = a[1] + ... + a[i]$$

如果我想查询区间 $[x,y] \ (y>x)$ 的和

$$\text{sum}=\text{prefix}[y]-\text{prefix}[x-1]$$

没什么好说的,随机应变

二维前缀和

结论

$$\text{prefix}[i][j] = a[i][j] + \text{prefix}[i-1][j] + \text{prefix}[i][j-1] - \text{prefix}[i-1][j-1]$$

给定左上角 $(x_1, y_1)$ ,右下角 $(x_2, y_2)$ ,矩阵和为:

$$\text{sum} = \text{prefix}[x_2][y_2] - \text{prefix}[x_1-1][y_2] - \text{prefix}[x_2][y_1-1] + \text{prefix}[x_1-1][y_1-1]$$

#include<bits/stdc++.h>
using namespace std;
int n,m;
int a[1005][1005],prefix[1005][1005];
int main(){
    cin>>n>>m;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            cin>>a[i][j];
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            prefix[i][j]=a[i][j]+prefix[i-1][j]+prefix[i][j-1]-prefix[i-1][j-1];
    int x1,y1,x2,y2;
    cin>>x1>>y1>>x2>>y2;
    cout<<prefix[x2][y2]-prefix[x1-1][y2]-prefix[x2][y1-1]+prefix[x1-1][y1-1]<<endl;
}

理解直观表示

这里可以生成一个n*n的前缀和数组方便理解,把鼠标放在格子上有选中特效

简易理解: $\text{prefix}[i][j]表示了(0,0)至(i,j)范围矩阵中内除了自身所有节点的和$

这里有个工具可以渲染计算前缀和查询区间操作的推导示意图,黄色部分是蓝色部分和绿色部分的交叉部分

二维前缀和可视化程序

三维前缀和

评价:极其复杂,考到了就现推吧

递推式

$$\begin{aligned}
prefix[i][j][k]
&= a[i][j][k] \\
&\quad + prefix[i-1][j][k] + prefix[i][j-1][k] + prefix[i][j][k-1] \\
&\quad - prefix[i-1][j-1][k] - prefix[i-1][j][k-1] - prefix[i][j-1][k-1] \\
&\quad + prefix[i-1][j-1][k-1].
\end{aligned}$$

for(int i=1;i<=X;i++)
    for(int j=1;j<=Y;j++)
        for(int k=1;k<=Z;k++)
            p[i][j][k] = p[i-1][j][k] + p[i][j-1][k] + p[i][j][k-1]
                         - p[i-1][j-1][k] - p[i-1][j][k-1] - p[i][j-1][k-1]
                         + p[i-1][j-1][k-1] + a[i][j][k];

查询操作

要查询区间

$$[x_1..x_2]\times[y_1..y_2]\times[z_1..z_2]$$

之和,需对 prefix 做 8 次 “加减” 运算:

$$\begin{aligned}
\mathrm{sum}
&= prefix[x_2][y_2][z_2] \\
&\quad - prefix[x_1-1][y_2][z_2] - prefix[x_2][y_1-1][z_2] - prefix[x_2][y_2][z_1-1] \\
&\quad + prefix[x_1-1][y_1-1][z_2] + prefix[x_1-1][y_2][z_1-1] + prefix[x_2][y_1-1][z_1-1] \\
&\quad - prefix[x_1-1][y_1-1][z_1-1].
\end{aligned}$$

  • 第 1 项:整个前缀和

  • 第 2–4 项:减去在 x、y、z 维超出下界的三个半面

  • 第 5–7 项:加回被多减的三个交叉边

  • 第 8 项:减去多加的“角”

int sum = p[x2][y2][z2]
          - p[x1-1][y2][z2] - p[x2][y1-1][z2] - p[x2][y2][z1-1]
          + p[x1-1][y1-1][z2] + p[x1-1][y2][z1-1] + p[x2][y1-1][z1-1]
          - p[x1-1][y1-1][z1-1];

小结

复杂度分析

维度 预处理时间复杂度 空间复杂度 单次查询复杂度 查询公式(以闭区间 $[l,r]$ 或矩形 $(x_1,y_1)-(x_2,y_2)$ 为例)
一维 $O(n)$ $O(n)$ $O(1)$ $\text{prefix}[r] - \text{prefix}[l - 1]$
二维 $O(n \times m)$ $O(n \times m)$ $O(1)$ $\text{prefix}[x_2][y_2] - \text{prefix}[x_1-1][y_2] - \text{prefix}[x_2][y_1-1] + \text{prefix}[x_1-1][y_1-1]$
三维 $O(n \times m \times h)$ $O(n \times m \times h)$ $O(1)$ 类似二维,公式较长(见下)

$$\begin{aligned}
\text{sum} =&\ \text{prefix}[x_2][y_2][z_2] \\
& -\ \text{prefix}[x_1-1][y_2][z_2] - \text{prefix}[x_2][y_1-1][z_2] - \text{prefix}[x_2][y_2][z_1-1] \\
& +\ \text{prefix}[x_1-1][y_1-1][z_2] + \text{prefix}[x_1-1][y_2][z_1-1] + \text{prefix}[x_2][y_1-1][z_1-1] \\
& -\ \text{prefix}[x_1-1][y_1-1][z_1-1]
\end{aligned}$$

应用(From GPT)

技术/变种 简介 查询复杂度
差分数组(1D/2D/3D) 快速处理区间/区域修改 $O(1)$ 单次修改,额外一次前缀和恢复
前缀最大值/最小值 类似思想但用于 RMQ,非加法可加性 需线段树等支持,复杂度提高
树状数组 / 线段树 支持修改 + 查询 $O(\log n)$
一维可持久化前缀和 支持历史版本 $O(\log n)$ 空间换版本

差分

一维差分

$$a[i] = \sum_{j=1}^{i} diff[j] \quad \text{或者等价地:} \quad diff[i] = a[i] - a[i-1]$$

构造

for(int i=1;i<=n;i++)
    diff[i]=a[i]-a[i-1];

单次区间操作

假设操作区间 $[l,r]$

diff[l] += k;
diff[r+1] -= k;

还原

还原原数组

a[0] = 0;
for(int i=1;i<=n;i++)
    a[i]=a[i-1]+diff[i];

二维差分

$$\text{diff}[i][j] = a[i][j] - a[i-1][j] - a[i][j-1] + a[i-1][j-1]$$

构造

for(int i=1;i<=n;i++)
    for(int j=1;j<=m;j++)
        diff[i][j]=a[i][j]-a[i-1][j]-a[i][j-1]+a[i-1][j-1];

单次区间操作

diff[x1][y1]     += k;
diff[x2+1][y1]   -= k;
diff[x1][y2+1]   -= k;
diff[x2+1][y2+1] += k;

还原原数组

for(int i=1;i<=n;i++)
    for(int j=1;j<=m;j++)
        a[i][j]=a[i-1][j]+a[i][j-1]-a[i-1][j-1]+diff[i][j];

三维差分

$$\begin{aligned}
diff[i][j][k]
&= a[i][j][k] \\
&\quad - a[i-1][j][k] - a[i][j-1][k] - a[i][j][k-1] \\
&\quad + a[i-1][j-1][k] + a[i-1][j][k-1] + a[i][j-1][k-1] \\
&\quad - a[i-1][j-1][k-1].
\end{aligned}$$

$$\begin{cases}
diff[x_1][y_1][z_1] \mathrel{+}= k \\
diff[x_2+1][y_1][z_1] \mathrel{-}= k \\
diff[x_1][y_2+1][z_1] \mathrel{-}= k \\
diff[x_1][y_1][z_2+1] \mathrel{-}= k \\
diff[x_2+1][y_2+1][z_1] \mathrel{+}= k \\
diff[x_2+1][y_1][z_2+1] \mathrel{+}= k \\
diff[x_1][y_2+1][z_2+1] \mathrel{+}= k \\
diff[x_2+1][y_2+1][z_2+1] \mathrel{-}= k
\end{cases}$$

实际上就是前缀和的逆运算

for(int i=1;i<=X;i++)
  for(int j=1;j<=Y;j++)
    for(int k=1;k<=Z;k++)
      diff[i][j][k]=a[i][j][k]-a[i-1][j][k]-a[i][j-1][k]-a[i][j][k-1]
                    +a[i-1][j-1][k]+a[i-1][j][k-1]+a[i][j-1][k-1]-a[i-1][j-1][k-1];

单次区间操作

diff[x1][y1][z1]     += k;
diff[x2+1][y1][z1]   -= k;
diff[x1][y2+1][z1]   -= k;
diff[x1][y1][z2+1]   -= k;
diff[x2+1][y2+1][z1] += k;
diff[x2+1][y1][z2+1] += k;
diff[x1][y2+1][z2+1] += k;
diff[x2+1][y2+1][z2+1] -= k;

还原原数组

for(int i=1;i<=X;i++)
  for(int j=1;j<=Y;j++)
    for(int k=1;k<=Z;k++)
      a[i][j][k]=a[i-1][j][k]+a[i][j-1][k]+a[i][j][k-1]
                 -a[i-1][j-1][k]-a[i-1][j][k-1]-a[i][j-1][k-1]
                 +a[i-1][j-1][k-1]+diff[i][j][k];

小结

复杂度分析

维度 构建复杂度 修改复杂度(单次区间/区域更新) 查询复杂度(单点或区间求和) 空间复杂度 说明
一维 $O(n)$ $O(1)$ $O(n)$(单点还原) $O(n)$ 修改时直接更新差分数组对应两个点;查询时需从差分还原前缀和。
一维(结合前缀和) $O(n)$ $O(1)$ $O(1)$ $O(n)$ 维护差分数组和前缀和数组,查询单点或区间均为 $O(1)$。
二维 $O(n \times m)$ $O(1)$ $O(n \times m)$(还原) $O(n \times m)$ 修改时更新差分数组的四个角点;查询时需要还原原数组。
二维(结合前缀和) $O(n \times m)$ $O(1)$ $O(1)$ $O(n \times m)$ 维护差分数组和前缀和数组,快速查询区域和。
三维 $O(n \times m \times h)$ $O(1)$ $O(n \times m \times h)$(还原) $O(n \times m \times h)$ 修改时更新八个角点;查询时还原较慢。
三维(结合前缀和) $O(n \times m \times h)$ $O(1)$ $O(1)$ $O(n \times m \times h)$ 结合前缀和数组快速查询。

应用(From GPT)

应用方向

说明

典型问题举例

区间快速增减

在不修改原数组的情况下,快速实现对某个区间(或区域)整体加减操作

- 维护一个数组,支持多次区间+1操作,最后输出结果- 大量区间修改的问题,如“区间加法”

区间批量修改

适合处理多次批量区间增减后,最后统一查询或输出数组最终状态

- 处理多个区间的修改,减少逐点更新开销- 颜色涂色、区域涂抹类题目

二维/三维区域更新

通过差分四角点或八角点实现对二维矩阵或三维立方体的快速区域修改

- 地图或棋盘区域批量加值- 三维体积中区域叠加处理

高效模拟批量事件

快速将多次批量事件合并,避免重复计算,最后统一还原结果

- 多个事件叠加影响的累计求和- 快速模拟时间段内的批量数据修改

前缀和结合优化查询

结合前缀和使用,可实现单次区间修改和单点/区间查询均为 O(1)O(1)

- 需要同时支持区间修改和区间查询(如部分竞赛题或数据结构扩展)

本文写作过于匆忙,以后有机会会维护