浅谈差分数组
本篇随笔简单讲解一下信息学奥林匹克竞赛中差分算法及差分数组的应用。读者在阅读本随笔前最好拥有一些基本的算法竞赛的知识,了解如前缀和、数组等基本数据结构。这将会使你的阅读体验变得更佳舒适。
差分数组的定义
来看一个例子:
原数组(a:5,8,4,3,15)
差分数组 (b:5,3,-4,-1,12)
发现了什么没?
差分数组就是原数组对应项和它前面那项的差值。
这里会有一个性质:
原数组中的第(i)项就等于:
这是显然的。
差分前缀和
还是先来看例子:
原数组:(a:5,8,4,3,15)
它的前缀和数组:(c:5,13,17,20,35)
它的差分数组:(b:5,3,-4,-1,12)
它的差分前缀和(就是差分数组的前缀和):(d:5,8,4,3,15)
我们发现,差分前缀和就是原数组。这个性质可以通过上面的性质(sum_{j=1}^{j=i}b[j])得出。
差分数组的应用
看起来差分并没有那么难。但是差分思想博大精深。
我们看一道题:
对一个区间,我们每一次操作将([l,r])这段区间上的所有数加上(delta)。
最后查询某一个区间的和。
如果考虑暴力修改的话,时间复杂度是(O(nm))的。过不了。
那么我们考虑线段树和树状数组差分。
根据我们刚刚研究出来的差分的性质,我们发现,因为我们差分数组只维护了相邻两个元素的差值,但是因为是区间修改,所以这段区间内部相邻元素的差值其实是没有被改变的。也就是说,差分数组中发生改变的元素仅是第一个元素和最后一个元素+1(这里好好理解一下)
也就是说,我们只需要把差分数组(b)中的(b[l],b[r+1])加上(delta),就可以做到在(O(2))的时间进行区间修改。
但是!!
刚刚把“最后查询”打上黑体是有原因的。因为如果在操作中多次进行查询操作,就需要多次统计,而差分只是优化了修改的复杂度,查询的复杂度还是(O(n))的,所以如果是多次查询的话,就需要线段树、树状数组等数据结构优化了。