目前网站开发趋势seo搜索优化工程师招聘
目录
- 差分:
- 思路
- 代码:
原题链接
差分:
输入一个长度为 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;}