当前位置: 首页 > news >正文

【一维 前缀和+差分】

一、一维前缀和

1.1 定义

给定一个数组 a[1..n],其前缀和数组 pre[1..n] 定义为:

pre[i]=a[1]+a[2]+⋯+a[i] pre[i] = a[1] + a[2] + \dots + a[i] pre[i]=a[1]+a[2]++a[i]

pre[i] 表示原数组从第 1 项到第 i 项的和。

1.2 构建

int a[N], pre[N];
for (int i = 1; i <= n; i++) 
{pre[i] = pre[i - 1] + a[i];
}

1.3 区间求和

使用前缀和可以在 O(1)O(1)O(1) 时间内求任意区间 [l,r][l, r][l,r] 的和:

sum=pre[r]−pre[l−1] sum = pre[r] - pre[l - 1] sum=pre[r]pre[l1]

公式推导:

pre[r]=a[1]+a[2]+⋯+a[l−1]+a[l]+⋯+a[r]pre[l−1]=a[1]+a[2]+⋯+a[l−1] pre[r] = a[1] + a[2] + \dots + a[l-1] + a[l] + \dots + a[r] \\ pre[l-1] = a[1] + a[2] + \dots + a[l-1] pre[r]=a[1]+a[2]++a[l1]+a[l]++a[r]pre[l1]=a[1]+a[2]++a[l1]

所以两者一减,刚好剩下区间 [l,r][l, r][l,r] 的和。

1.4 应用场景

  • 快速计算区间和
  • 优化暴力 O(n2)O(n^2)O(n2) 的区间统计问题为 O(n)O(n)O(n)

1.5 示例

// 输入一个数组,求多个区间 [l, r] 的和
int a[N], pre[N];
cin >> n >> q;
for (int i = 1; i <= n; i++) cin >> a[i];
for (int i = 1; i <= n; i++) pre[i] = pre[i - 1] + a[i];while (q--) 
{int l, r;cin >> l >> r;cout << pre[r] - pre[l - 1] << '\n';
}

二、一维差分数组

2.1 定义

对于原数组 a[1..n],其差分数组 diff[1..n] 定义为:

diff[i]=a[i]−a[i−1]  (i≥2),  diff[1]=a[1] diff[i] = a[i] - a[i - 1]\ \ (i \geq 2),\ \ diff[1] = a[1] diff[i]=a[i]a[i1]  (i2),  diff[1]=a[1]

2.2 构建

int a[N], diff[N];
diff[1] = a[1];
for (int i = 2; i <= n; i++) 
{diff[i] = a[i] - a[i - 1];
}

2.3 区间加法操作

若想对区间 [l,r][l, r][l,r] 所有数加上 ddd,只需:

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

原理在于:差分数组记录的是“增量”,只需要在区间起点加一个数、在区间终点的下一位减去这个数,就能确保中间所有位置都累加这个值。

然后通过前缀和还原整个数组:

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

2.4 区间减法操作

若想对区间 [l,r][l, r][l,r] 所有数减去 ddd,也可以使用差分数组:

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

原理类似:差分数组记录的是“增量”,如果我们想对一个区间 [l,r][l, r][l,r] 的所有元素减去 ddd,只需要在区间起点加上 −d-dd,在区间终点的下一位加上 +d+d+d,就能确保整个区间内的值都减少 ddd,而其他位置不受影响。这与区间加法操作完全对称,只是将 ddd 替换为 −d-dd


三、差分原理

3.1 目的

差分数组的核心目的是:将原本需要 O(n) 的区间修改操作优化为 O(1)

比如:我们想对数组中一段区间 [l,r][l, r][l,r] 的所有元素都加上一个数 ddd,若用原数组暴力加法,每次操作就要 O(r−l+1)O(r-l+1)O(rl+1);当有 mmm 次操作时,总复杂度是 O(mn)O(mn)O(mn),会超时。

3.2 差分数组的构建

我们构建一个数组 diff[1…n]diff[1 \ldots n]diff[1n]

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

也可以理解为:

差分数组记录的是原数组中相邻两项之间的“变化量”。

根据这个定义,有:

a[i]=diff[1]+diff[2]+⋯+diff[i]⇒a[i]=∑j=1idiff[j] a[i] = diff[1] + diff[2] + \dots + diff[i] \Rightarrow a[i] = \sum_{j=1}^{i} diff[j] a[i]=diff[1]+diff[2]++diff[i]a[i]=j=1idiff[j]

也就是说,原数组可以通过差分数组做前缀和来还原

3.3 差分操作的核心逻辑

想要将区间 [l,r][l, r][l,r] 所有数都加上 ddd,我们可以在 diff[] 上做如下处理:

diff[l] += d;
diff[r + 1] -= d;
为什么这样就能完成整个区间的加法?

我们回忆差分的“还原”过程:

a[1] = diff[1];
a[2] = a[1] + diff[2];
a[3] = a[2] + diff[3];
...

你会发现,前缀相加会让 diff[l] 的影响一直传导下去。直到 diff[r+1] 把这部分影响抵消为止。

也就是说:

  • a[l]a[l]a[l]a[r]a[r]a[r] 都被加上了 ddd
  • a[r+1]a[r+1]a[r+1] 之后的数不受影响

这就实现了:O(1) 修改一个区间


四、一个形象的类比

假设你站在楼梯上,从第 1 级楼梯往上走,a[i] 是你在第 i 级台阶上的高度。

  • 前缀和:相当于你每走一步都记一下总共走了多远。
  • 差分数组:相当于你记录每一步你上升(或下降)了多少。

你只要知道每一步的变化量(差分数组),就能还原出每一级台阶的实际高度(原数组);你也能知道在一段范围内你升高了多少(前缀和)。



五、前缀和与差分的区别与联系

类别作用技术本质时间复杂度
前缀和快速查询区间和把每个位置存成前缀累加和查询 O(1)O(1)O(1),构建 O(n)O(n)O(n)
差分数组快速区间修改存储相邻值之间的“变化”修改 O(1)O(1)O(1),恢复 O(n)O(n)O(n)

它们的关系就像:

  • 前缀和是累计的“总和”
  • 差分是相邻的“变化量”

差分数组其实就是前缀和的逆操作。


六、常见问题汇总

  1. 差分数组的还原为什么用前缀和?

    差分数组记录的是相邻元素之间的增量,所以前缀和就是原数组。

  2. 差分数组是否支持区间乘法?

    不支持,差分只能处理区间加减。

  3. 差分数组是否可以从 0 开始?

    可以,但要注意下标对应的意义,最好从 1 开始更清晰。

  4. 是否每次都需要重建差分数组?

    看情况。如果每次操作互不干扰,可以复用;否则建议重建或静态开数组并清空。


七、总结

  • 前缀和用于高效区间查询
  • 差分数组用于高效区间修改
  • 两者配合使用是处理“区间加减 + 查询”类问题的利器

在处理数据量较大的题目(如 10510^510510610^6106)时,前缀和与差分是比线段树更快、更简洁的选择。

http://www.lryc.cn/news/588370.html

相关文章:

  • 【牛客刷题】小红的数字删除
  • 第 2 章 数据类型及其运算
  • 内测分发平台应用的异地容灾和负载均衡处理和实现思路
  • 【深度学习笔记】2 浅层神经网络
  • Dubbo 学习笔记
  • python接口自动化 - 使用requests库发送http请求
  • Datawhale AI夏令营——用户新增预测挑战赛
  • Docker入门指南(超详细)
  • 华为OD 消消乐游戏
  • LLaMA.cpp HTTP 服务参数: --pooling 嵌入模型 池化类型详解
  • 【时时三省】(C语言基础)用数组名作函数参数
  • 75、【OS】【Nuttx】【启动】caller-saved 和 callee-saved 示例
  • 数电汇总——logisim的辛酸史
  • 【Python进阶】深度复制——deepcopy
  • stm32-Modbus主机移植程序理解以及实战
  • JSCPC 2025 江苏省赛
  • 制造业实战:数字化集采如何保障千种备件“不断供、不积压”?
  • Java从入门到精通!第五天(面向对象(二))
  • 《解锁音频处理新姿势:探索Librosa的无限可能》
  • HarmonyOS应用无响应(AppFreeze)深度解析:从检测原理到问题定位
  • ISO-IEC-IEEE 42010架构规范
  • 016 进程控制 —— 进程创建
  • ShenYu实战、问题记录
  • Spring Boot 自带的 JavaMail 集成
  • 文心一言 4.5 开源深度剖析:中文霸主登场,开源引擎重塑大模型生态
  • 分布式光伏并网中出现的电能质量问题,如何监测与治理?
  • 时序预测 | Pytorch实现CNN-LSTM-KAN电力负荷时间序列预测模型
  • MongoDB从入门到精通
  • [Nagios Core] 事件调度 | 检查执行 | 插件与进程
  • 【Linux】Linux 操作系统 - 28 , 进程间通信(四) -- IPC 资源的管理方式_信号量_临界区等基本概念介绍