顾名思义,就是在[l,r]区间上加上首项为k,公差为d的等差数列。分为以下这么三类情况:
先加后询问 #
即先加,最后再输出整个数组,或者询问的位置和修改的左端点是有序的。这种情况我们不需要借助其他数据结构,有以下两种思路:
靠思维 #
我们先回顾一下区间加同样的数是怎么做的,我们维护当前加在原数组上的值,并用一个数组add标记维护的值在i位置该如何变化,比如说给[l,r]加上x,我们令a[l] += x, a[r+1] -= x
,这样[l,r]中的数都会加x,然后r−1位置还原。
加等差数列就是上述思路的扩展,我们不仅维护当前加在原数组上的值cur,还维护当前的公差inc,以及用两个数组cur_add和inc_add标记两个维护的值的变化。当加一个等差数列时,我们在l处标记d代表从l处开始公差加d,在r+1处标记−d以复原公差。cur也需要类似的标记:在l处标记k,在r+1处标记−(k+(r−l+1)⋅d)。总结一下:
靠数学 #
分析一下差分数组
下标 | l−1 | l | l+1 | l+2 | … | r | r+1 | r+2 |
---|
原数组 | 0 | k | k+d | k+2d | | k+(len−1)d | 0 | 0 |
一阶差分 | 0 | k | d | d | | d | −(k+(len−1)d) | 0 |
二阶差分 | 0 | k | d−k | 0 | | 0 | −(k+len⋅d) | k+(len−1)d |
不难看出二阶差分数组上产生了四次单点修改。所以我们先在二阶差分数组上修改最后再跑两次前缀和即可得到最后的数组。
放个例题CF1661D
区间修改,单点查询 #
此时我们就需要数据结构维护差分数组了
维护一阶差分数组 #
观察上面一阶差分可以发现有两个单点修改一个区间修改,ai是一阶差分的前缀和,所以用区间修改区间查询的数据结构即可(线段树,树状数组)
维护二阶差分数组 #
我们需要单点修改然后二阶前缀和,二阶前缀和可以拆成两个前缀和:
bi=1∑iai,ci=1∑ibi
ci =ia1+(i−1)a2+⋯+2ai−1+ai=(i+1)(a1+a2+⋯+ai)−(a1+2a2+⋯+iai)
维护ai和iai的前缀和即可。
例题:洛谷 P1438 无聊的数列
区间修改,区间查询 #
要是搞三阶前缀和那可能略显麻烦了,我们不妨转变思路用线段树,其实与正常的区间加类似,懒惰标记变成了这个区间加的等差数列的首项和公差。