0%

区间赋值

区间赋值

问题描述

Select n cities from the world map, and a[i] represents the asset value owned by the i-th city.
Then there will be several operations. Each turn is to choose the city in the interval [l, r] and increase their asset value by c. And finally, it is required to give the asset value of each city after q operations.
------------------------------------------------------
从世界地图从选出 n 个城市,a[i]表示选出的第 i 个城市的值。
接下来会有 q 个操作。每一次从区间[l, r]中选出城市,并把它们的值提高 c。
最终求得各个城市的值。

Input

The first line contains two integers n,q (1 ≤ n,q ≤ 2⋅10^5) — the number of cities and operations.
The second line contains elements of the sequence a: integer numbers a1, a2, ..., an (−10^6 ≤ ai ≤ 10^6).
Then q lines follow, each line represents an operation. The i-th line contains three integers l, r and c (1 ≤ l ≤ r ≤ n, −10^5 ≤ c ≤ 10^5) for the i-th operation.
------------------------------------------------------
第一行两个整数 n, q (1 ≤ n,q ≤ 2⋅10^5),表示城市数和操作数。
第二行 n 个整数,表示城市 a1, a2, ..., an (−10^6 ≤ ai ≤ 10^6)。
接下来的 q 行,每一行代表一个操作,每一行包括3个整数 l, r 和 c (1 ≤ l ≤ r ≤ n, −10^5 ≤ c ≤ 10^5)。

Output

Print n integers a1,a2,…,an one per line, and ai should be equal to the final asset value of the i-th city.
------------------------------------------------------
输出n个整数,a1, a2, …, an。

Sample

input: 
4 2
-3 6 8 4
4 4 -2
3 3 1
output:
-3 6 9 2

input:
2 1
5 -2
1 2 4
output:
9 2

input:
1 2
0
1 1 -8
1 1 -6
output:
-14

Limitation

Time limit		1000 ms
Memory limit 262144 kB

解题思路

q 次操作区间,每次对区间内每个数进行加/减操作,暴力做法就是每次赋值操作都来一个for循环,时间复杂度为O(qn),考虑到数据范围,会超时。

这边就要用到差分跟前缀和。

差分:原数组第二个元素起,每个元素与前一元素之差形成一个新数组。如:
原数组a[n], 新数组b[n], b[1] = a[1], b[i] = a[i] - a[i-1] (i ≥2)

前缀和可以在O(1)时间复杂度内求一个区域内所有元素之和,利用差分数组只进行单点修改,可以更新一个区域内的数值。

比如第一个样例,原数组a[4] = {-3, 6, 8, 4}, 差分数组b[4] = {-3, 9, 2, -4}
第一次操作:第4个数降值2,a'[4] = {-3, 6, 8, 2}, b'[4] = {-3, 9, 2, -6}
第二次操作:第3个数增值1,a''[4] = {-3, 6, 9, 2}, b'' = {-3, 9, 3, -7}, 前缀和生成数组c[4] = {-3, 6, 9, 2}, 与a''相同。

本题由于数据范围,如果使用int在test 17会WA,所以得用long long

源代码

#include <cstdio>
using namespace std;

int main() {
long long n, q;//n个数 q个操作
scanf_s("%lld%lld", &n, &q);
long long* arr = new long long[n + 10];//原数组
for (int i = 0; i < n; i++)
scanf_s("%lld", &arr[i]);
long long* arr1 = new long long[n + 10];//差分数组
arr1[0] = arr[0];
for (int i = 1; i != n; i++)
arr1[i] = arr[i] - arr[i - 1];//求得差分
for (int i = 0; i < q; i++) {//q次操作
int l, r, c;
scanf_s("%d%d%d", &l, &r, &c);
arr1[l - 1] += c;
arr1[r] -= c;
}
long long* arr2 = new long long[n + 10];//前缀和成数组
arr2[0] = 0;
for (int i = 1; i != n; i++)
arr2[i] = arr2[i - 1] + arr1[i];//前缀和
printf("%lld ", arr1[0]);
for (int i = 1; i != n; i++)
printf("%lld ", arr2[i] + arr1[0]);
printf("\n");
return 0;
}