#include <iostream>
#include <vector>
using namespace std;
int main() {
int n, m;
cin >> n >> m;
vector<long long> a(n + 2); // a[1..n]
for (int i = 1; i <= n; ++i) {
cin >> a[i];
}
// !!构建差分数组 d[1..n+1]
vector<long long> d(n + 2, 0);
for (int i = 1; i <= n; ++i) {
d[i] = a[i] - a[i - 1];
}
// m 次操作,每次修改区间 [l, r] 加上 k
for (int i = 0; i < m; ++i) {
int l, r;
long long k;
cin >> l >> r >> k;
d[l] += k;
d[r + 1] -= k;
}
// 还原最终数组:前缀和
for (int i = 1; i <= n; ++i) {
a[i] = a[i - 1] + d[i];
cout << a[i] << " ";
}
cout << endl;
return 0;
}
朴素写法是:
for (int i = l; i <= r; ++i) {
a[i] += k;
}
⛔ 坏处:每次操作都是 O(r−l+1),多次就会超时。
✅ 差分数组思想:用一种技巧,让区间修改变成“常数时间”
我们定义一个新的数组 d[i],表示:
d[i] = a[i] - a[i-1]
也就是说,d 数组是 a 数组的“变化量”。
举个例子:
a = [1, 2, 3, 4, 5] => d = [1, 1, 1, 1, 1] (因为 a[i]-a[i-1] 都是1)
现在我们想把区间 [2,4] 加上 10,该怎么办呢?
只需要改两项:
d[2] += 10; d[5] -= 10; // 4的下一位是5
🤔 为什么这样就可以?
假设你后面用前缀和恢复回 a:
a[1] = d[1] a[2] = d[1] + d[2] a[3] = d[1] + d[2] + d[3] ...
所以这个差分数组在恢复的时候会自动把 [2, 3, 4] 都加上 10。
来看完整过程:
原数组: [1, 2, 3, 4, 5] 原差分 d: [1, 1, 1, 1, 1] 修改 d: d[2] += 10, d[5] -= 10 更新后 d: [1, 11, 1, 1, -9] 前缀还原 a: a[1] = 1 a[2] = 1 + 11 = 12 a[3] = 1 + 11 + 1 = 13 a[4] = 1 + 11 + 1 + 1 = 14 a[5] = 1 + 11 + 1 + 1 - 9 = 5 结果: [1, 12, 13, 14, 5] ✅

京公网安备 11010502036488号