描述

给你一个长度为NC7 【模板】差分 - 图1的正数数组NC7 【模板】差分 - 图2
接下来对这个数组进行NC7 【模板】差分 - 图3次操作,每个操作包含三个参数NC7 【模板】差分 - 图4,代表将数组中位置位于区间NC7 【模板】差分 - 图5的元素都加上NC7 【模板】差分 - 图6
请输出操作后的数组。

输入描述:

第一行包含两个整数NC7 【模板】差分 - 图7NC7 【模板】差分 - 图8
第二行包含NC7 【模板】差分 - 图9个整数表示NC7 【模板】差分 - 图10
接下来是NC7 【模板】差分 - 图11行,每行三个整数,分别代表每次操作的参数NC7 【模板】差分 - 图12

参数限制:

  • NC7 【模板】差分 - 图13
  • NC7 【模板】差分 - 图14
  • NC7 【模板】差分 - 图15
  • NC7 【模板】差分 - 图16

    输出描述:

    输出1行,表示NC7 【模板】差分 - 图17次操作后的NC7 【模板】差分 - 图18

解决思路:差分+数组的前缀和

  • 数组的前缀和(前n项和):prefixSum[i]表示数组nums中[0:i]范围内所有元素的和,利用动态规划prefixSum[i]=prefixSum[i-1]+nums[i]很容易算出。
  • 简单差分:考虑数组[1,3,5,7,9],
    • 假设有一组数l=2,r=3,k=+2,表明要对原数组的[5,7]分别加2;
    • 此时使用额外的数组diff(初始化为0)并记录diff[l]=diff[2]+=k=2,diff[r+1]=diff[4]+=-k=-2,也即diff=[0,0,2,0,-2];
    • 那么diff的前缀和数组即为[0,0,2,2,0],也就是l=2,r=3,k=+2操作后原数组各元素对应的改变量;
    • 而且这种操作是可累加的,也就是说,假设有2组操作数l=2,r=3,k=+2和l=1,r=3,k=-5,
      • 如果依次计算,则第一次操作后nums=[1,3,7,9,9],第二次操作后nums=[1,-2,2,4,9];
      • 使用差分和前缀和计算,第一次操作使得diff=[0,0,2,0-2],第二次操作使得diff=[0,-5,2,0,3];diff数组的前缀和数组为[0,-5,-3,-3,0],加上原数组元素[1,3,5,7,9]可得结果[1,-2,2,4,9],与原结果一致。
  • 所以使用差分和前缀和计算可以将时间复杂度压缩到NC7 【模板】差分 - 图19(O(m)是要依次计算m次操作后的diff数组,O(n)是要计算diff的前缀和数组),空间复杂度为NC7 【模板】差分 - 图20(diff数组,并该数组上计算前缀和)。
  • 暴力解法的时间复杂度为NC7 【模板】差分 - 图21,空间复杂度为NC7 【模板】差分 - 图22

代码实现

  1. #include <iostream>
  2. #include <vector>
  3. typedef long long DT;
  4. using namespace std;
  5. int main()
  6. {
  7. int n, m;
  8. cin >> n >> m;
  9. vector<DT> nums(n+1, 0);
  10. for(int i=1; i<=n; ++i){
  11. cin >> nums[i];
  12. }
  13. // 计算差分数组
  14. vector<DT> dp_diff(n+1, 0);
  15. int l, r, k;
  16. while(--m >= 0){
  17. cin >> l >> r >> k;
  18. dp_diff[l] += k;
  19. if(r+1 <= n){
  20. dp_diff[r+1] -= k;
  21. }
  22. }
  23. // 计算差分数组的前缀和
  24. for(int i=1; i<=n; i++){
  25. dp_diff[i] = dp_diff[i-1] + dp_diff[i];
  26. }
  27. for(int i=1; i<=n; i++){
  28. cout << nums[i] + dp_diff[i] << " ";
  29. }
  30. cout << endl;
  31. }