【一维 前缀和+差分】
一、一维前缀和
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[l−1]
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[i−1] (i≥2), diff[1]=a[1]
通过差分数组可以快速实现对一个区间 [l,r][l, r][l,r] 的所有值同时加上一个数 ddd。
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-d−d,在区间终点的下一位加上 +d+d+d,就能确保整个区间内的值都减少 ddd,而其他位置不受影响。这与区间加法操作完全对称,只是将 ddd 替换为 −d-d−d。
2.5 应用场景
- 多次区间加操作(比树状数组/线段树更快)
- 多次构造某种“影响”或“变化”的模型(如教室占用、涨价、染色)
2.6 示例
// 初始数组为 0,对多个区间加值,输出最终数组
int diff[N] = {0};
cin >> n >> m; // n 个元素,m 次操作
for (int i = 1; i <= m; i++)
{int l, r, d;cin >> l >> r >> d;diff[l] += d;diff[r + 1] -= d;
}// 还原结果数组
int a[N];
a[0] = 0;
for (int i = 1; i <= n; i++)
{a[i] = a[i - 1] + diff[i];cout << a[i] << ' ';
}
三、前缀和 vs 差分数组
技术 | 优势 | 典型操作 | 使用时机 |
---|---|---|---|
前缀和 | 快速区间求和 | 查询 [l,r][l,r][l,r] 区间和 | 多次查区间和 |
差分数组 | 快速区间加 | 区间加 ddd ororor −d-d−d | 多次改区间数值 |
它们两个往往成对出现,比如:
- 差分数组批量处理区间修改
- 再通过前缀和恢复最终值
四、常见问题汇总
-
差分数组的还原为什么用前缀和?
差分数组记录的是相邻元素之间的增量,所以前缀和就是原数组。
-
差分数组是否支持区间乘法?
不支持,差分只能处理区间加减。
-
差分数组是否可以从
0
开始?可以,但要注意下标对应的意义,最好从 1 开始更清晰。
-
是否每次都需要重建差分数组?
看情况。如果每次操作互不干扰,可以复用;否则建议重建或静态开数组并清空。
五、总结
- 前缀和用于高效区间查询
- 差分数组用于高效区间修改
- 两者配合使用是处理“区间加减 + 查询”类问题的利器
在处理数据量较大的题目(如 10510^5105 或 10610^6106)时,前缀和与差分是比线段树更快、更简洁的选择。