题意:
- 长度为 n 的数组(数组中元素 ∣ a i ∣ |a_i| ∣ai∣≤ 1 0 6 10^6 106),一共进行 q 次操作,1 ≤ n, q ≤ 2× 1 0 5 10^5 105;
- 每次操作给出 L,R,c,表示区间[L, R]中各个数均增加上 c(− 1 0 5 10^5 105≤ c ≤ 1 0 5 10^5 105);
- 求 q 次操作结束后,数组中各个元素值。
输入要求:
- 第1行输入数组长度 n 和操作次数 q;
- 第2行输入数组的 n 个元素;
- 第3~3+n-1行输入每次操作给出的 L,R,c。
输出要求:
- 一行输出操作结束后的数组各元素。
sample input:
4 2
-3 6 8 4
4 4 -2
3 3 1
sample output:
-3 6 9 2
思路:
- 首先想到暴力解题办法:每次操作时进行 (R - L + 1)次加法,但是数据量过大,会发生超时,所以需另寻他法;
- 所以这里应用了前缀和与差分的思想,将原数组变为差分数组,将(R - L + 1)次加法改为两次加减法,b[L] = b[L] + c,b[R+1] = b[R+1] - c,该操作等价为对区间内所有数进行加法操作。在完成 q 次操作之后,再将差分数组变为其对应的前缀和数组,该数组就是原数组完成操作后的模样。
- 注意事项:该题数据值较大,最大时可以达到2× 1 0 16 10^{16} 1016,会超出int值的范围,故需要将数组类型定义为 long long int 型,否则会报错。
代码:
#include <iostream>
using namespace std;
long long int a[200005];//原数组
long long int b[200005];//a的差分
long long int c[200005];//b的前缀和
long long int l, r, num;
int main() {
int n, q;
cin >> n >> q;
for (int i = 1; i <= n; i++) {
cin >> a[i];
}
for (int i = 1; i <= n; i++) {
if (i == 1)
b[i] = a[i];
else
b[i] = a[i] - a[i - 1];
}
for (int i = 0; i < q; i++) {
cin >> l >> r >> num;
b[l] = b[l] + num;
b[r + 1] = b[r + 1] - num;
}
for (int i = 1; i <= n; i++) {
if (i == 1)
c[i] = b[i];
else
c[i] = b[i] + c[i - 1];
}
for (int i = 1; i <= n; i++) {
cout << c[i] << " ";
}
}