1.前缀和
1.背景
前缀和最经典的入门例子就是
给定一个长度为n的数组,每次查询区间l到r中,区间元素的和。当n的范围较小或询问次数较少时可以暴力累加,但是当n大于10000,q大于10000的时候往往容易超时,那么这个时候就需要用前缀和来解决这个问题。(对于n的二次方的算法大概数据范围10000以上超时,n的三次方算法1000以上超时)
2.前缀和的概念
这个时候我们引入一个概念叫做前缀和,将其定义为数组b,对于元素bi表示a数组从a1累加到ai的和。(for (i=1;i<=n;i++)b[i]=b[i-1]+a[i];)
这个时候我们再回来看例子,对于每次的询问区间[l,r],答案就变成了b[r]-b[-1]。
3.广义的前缀和
跳脱出例题,我们如何在其他题目中应用前缀和呢,或者说我们如何进一步的去理解前缀和。
对于一个序列,我们可以暂时先将前面的某个东西累加(也可以是乘等操作)起来,当查询区间[l,r]时,我们考虑是否可以消除前l-1个东西对于后面的影响,如果能够实现则可以做前缀和。
2.差分
1.背景
差分的经典入门例子是
给定一个长度为n的数组,每次操作对于区间[l,r]的每个元素都加上k,最后输出这个数组。
2.差分的概念
这个时候我们定义一个数组d,对于元素di等于ai-a(i-1)(下标),对于操作区间[l,r]加上k,我们只需要d[l]=d[l]+k,d[r+1]=d[r+1]-k;
那么答案数组就是差分数组d的前缀和数组。
例如数组00000,对于区间[2,4]加上k变为0k00-k,那么前缀和之后会发现数组变为0kkk0。
如果不能理解差分,我们可以来举个栗子。
假如现在有5个小朋友,每个人手上分别有2,3,4,7,10个糖果,现在让每个小朋友先上交糖果,交几个糖果呢?上交的糖果数应为前一个小朋友拥有的糖果数量,即差分,变为2,1,1,3,3。那么如何变回原来的情况呢?自然是需要一个逆操作,就是给每个小朋友发(与前一个小朋友拥有糖果数量相同的)糖果,即前缀和,就会变成2,3,4,7,10。
再来考虑区间加,例如[2,4]加上2,按照差分规则,差分数组变成2,3,1,3,1,此时做前缀和,当第二个小朋友拥有的糖果数量变为5的时候,那么第三个小朋友的糖果数也随之增加,变为5+1=6。对于第4个小朋友现在的糖果数量变为9,如果继续累加第5个小朋友的糖果也变为12(原先9+3=12),这个时候我们就需要拿走2个糖果,即-2。