差分--差分数组快速计算L到R值相加后的数组

发布时间:2024年01月10日


原题链接

差分:

输入一个长度为 n
的整数序列。

接下来输入 m
个操作,每个操作包含三个整数 l,r,c
,表示将序列中 [l,r]
之间的每个数加上 c

请你输出进行完所有操作后的序列。

输入格式
第一行包含两个整数 n
和 m

第二行包含 n
个整数,表示整数序列。

接下来 m
行,每行包含三个整数 l,r,c
,表示一个操作。

输出格式
共一行,包含 n
个整数,表示最终序列。

数据范围
1≤n,m≤100000
,
1≤l≤r≤n
,
?1000≤c≤1000
,
?1000≤整数序列中元素的值≤1000
输入样例:
6 3
1 2 2 1 2 1
1 3 1
3 5 1
1 6 1
输出样例:
3 4 5 3 4 2

思路

这题按照常规的思路 那就是用for循环l到r直接到数字 时间复杂度比较高
差分
类似于数学中的求导和积分,差分可以看成前缀和的逆运算。

差分数组:

首先给定一个原数组a:a[1], a[2], a[3], a[n];

然后我们构造一个数组b : b[1] ,b[2] , b[3], b[i];

使得 a[i] = b[1] + b[2 ]+ b[3] +, + b[i]

也就是说,a数组是b数组的前缀和数组,反过来我们把b数组叫做a数组的差分数组。换句话说,每一个a[i]都是b数组中从头开始的一段区间和。

考虑如何构造差分b数组?

最为直接的方法

如下:

a[0 ]= 0;

b[1] = a[1] - a[0];

b[2] = a[2] - a[1];

b[3] =a [3] - a[2];

b[n] = a[n] - a[n-1];

图示:

我们只要有b数组,通过前缀和运算,就可以在O(n) 的时间内得到a数组 。

知道了差分数组有什么用呢? 别着急,慢慢往下看。

话说有这么一个问题:

给定区间[l ,r ],让我们把a数组中的[ l, r]区间中的每一个数都加上c,即 a[l] + c , a[l+1] + c , a[l+2] + c , a[r] + c;

暴力做法是for循环l到r区间,时间复杂度O(n),如果我们需要对原数组执行m次这样的操作,时间复杂度就会变成O(n*m)。有没有更高效的做法吗? 考虑差分做法。

始终要记得,a数组是b数组的前缀和数组,比如对b数组的b[i]的修改,会影响到a数组中从a[i]及往后的每一个数。

首先让差分b数组中的 b[l] + c ,a数组变成 a[l] + c ,a[l+1] + c, a[n] + c;

然后我们打个补丁,b[r+1] - c, a数组变成 a[r+1] - c,a[r+2] - c,a[n] - c;

为啥还要打个补丁?

因为原来将b[l]+c后 其l后面的每一个数字都会被影响 ,将b[r+1]-c后 r+1后面的数字的影响又被修改了回来

那么等于只有l到r的这一段区间内的值被影响

代码:

#include<iostream>

using namespace std;

const int N=1e5+10;

int a[N],b[N];
int main()
{
    int m=0,n=0;
    cin>>m>>n;
    for(int i=1;i<=m ;i++)
    {
        scanf("%d",&a[i]);
        b[i] = a[i]-a[i-1];
    }
    //只修改差分数组里面的值即可
    while(n--)
    {
        int l=0,r=0;
        int val=0;
        cin>>l>>r>>val;
        b[l] +=val;
        b[r+1] -=val;
    }
    //将差分数组里面的值同步到a数组里面去
    for(int i=1;i<=m ;i++)
    {
        a[i] =a[i-1]+b[i];
        printf("%d ",a[i]);
    }
    return 0;
    
}
文章来源:https://blog.csdn.net/weixin_52243202/article/details/135513593
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。