做到一道需要多次改变一个 数组 一个区间的值的题目,暴力地for一遍的话肯定会T掉
然后经过学长的讲解,差分 这个小可爱 就进入了我的视野中。
什么是差分
一个序列 1 2 3 4 5
把这个序列进行差分运算 就是使这个序列中每一个数字(除了第一个数字)变为这个数字本身减去他前一个数字的差
所以这个序列进行差分运算之后就变为 1 、2-1 、 3-2 、 4-3 、 5-4
也就是1 1 1 1 1
这样看来差分运算似乎并没有什么稀奇的,但是它的性质很神奇鸭!
我们把差分过程抽象出来 把它一般化
有一个序列a1,a2,a2…an
对它进行差分 就变成了a1 ,a2-a1 ,a3-a2…,an-a(n-1) <–这个括号里是指下标,大家自行理解一下叭
差分后的序列 前i项和
sum=a1+(a2-a1)+(a3-a2)+…+(a(i-1)-a(i-2))+(ai-a(i-1))
=a1+a2-a1+a3-a2+…+a(i-1)-a(i-2)+ai-a(i-1)
相信聪明的大家一定发现了1到 i - 1 项都被消掉了,最后只剩下了ai
这就是差分神奇的性质啦
差分后序列的前 i 项和等于差分前第 i 个元素(咳咳,敲黑板啦!)
讲完了差分这个神奇的性质,然后还要讲一个差分在数组区间修改中的一个神操作
还是刚才的那个序列1 2 3 4 5
如果现在需要对这个序列的 [ l,r ] 区间上所有元素都加上x,并且要进行多次这样的操作,最后来求这整个序列的最小值。
大家一开始可能都会想到暴力for一遍 [ l, r ] 来修改区间元素值,但是这样时间效率实在是太低了,如果每一次操作区间都是1到n,并且操作次数很多的话就很容易T掉,所以我们就要寻求一下更简单的做法,大家不可以这么暴力,我们要对电脑温柔一点w
这时候就要用到我们的差分啦
首先我们还是举例说明,说清楚之后再推广到一般
初始序列 1 2 3 4 5
初始差分序列 1 1 1 1 1
如果需要对第2到4个数进行加1的操作
操作后 1 3 4 5 5
操作后差分序列 1 2 1 1 0
我们盯着第2到4个数的操作前后的差分序列看,有木有发现什么神奇的事情
大家可以试一试其他的观察一下
观察后我们发现:
操作改变的区间,只有区间第一个元素,以及区间最后一个元素的后一个元素的差分结果改变,其他差分结果均不改变
可能有点绕口,大家结合上面的例子再咀嚼一下下下。
这是为神魔捏
这是可是有理有据的,believe me ,please!
我们现在推广到一般证明一下子
原序列为a1 , a2 , a3 , … , aL , a(L+1) , … , a(R-1) , aR , … , a(n-1) , an
原差分序列为
a1 , (a2-a1) , (a3-a2) , … , ( aL - a(L-1) ) , ( a(L+1) - aL), … , ( a(R-1) - a(R-2) ) , ( aR - a(R-1) ) , ( a(R+1) - aR ) , … , ( a(n-1) - a(n-2) ) , ( an - a(n-1) )
现在要对区间 [ L , R ] 进行加 x 的操作
操作后序列变为a1,a2,a3,…,aL+x , a(L+1)+x , … , a(R-1)+x , aR+x , … , a(n-1) , an
操作后差分序列变为
a1 , (a2-a1) , (a3-a2) , … , ( aL - a(L-1) )+x , ( a(L+1) - aL) , … , ( a(R-1) - a(R-2) ) ,
( aR - a(R-1) ) , ( a(R+1) - aR )-x , … , ( a(n-1) - a(n-2) ) , ( an - a(n-1) )
原因如下
这样的发现让我们的区间修改摇身一变变成了O(1)的操作
(O(1)啊!!!!是不是很诱人!!!)
我们对于这样的问题