前缀和与差分的引入

前缀和

例1

        读入一个班n个同学的成绩,之后读入一个数q,表示q次询问,每次询问当一个同学分数为x时,他排多少名。

        很明显,挨个数时间复杂度太高。只需要统计大于等于x分的人数即可得到该同学的名次。可以使用greater[i]数组维护,方式是不断加上分数大于等于i的人数。举例说明:考1、 2、 3、 4、 5分(分可真低)的人数分别为4、 2、 3、 5、 1人,那大于等于1、 2、 3、 4、 5分的人数即为a[1]=15  a[2]=11  a[3]=9  a[4]=6  a[5]=1。如果一名同学考了3分,直接用大于等于3分的人数减去等于3分的人数再+1即可(直接维护大于x分的人数好像更香QwQ,但仔细想想还是要将大于x分的人数+1才行,简便程度差不多)。

        将对整个区间的查询转化为对区间端点的查询,这种思想就是前缀和的核心。要求对于区间操作尽可能往这里想。

       前缀和可用于求区间和。我们还可以发现,不仅可以通过sum数组轻松求出同学的总成绩,甚至可以询问分数在[x,y]区间内的同学有多少个。方式就是用sum[x]-sum[y-1](即用大于等于x的人数减去大于等于y-1的分数的人数)。以下为经典模板:

        已知数列{an},有q次询问,每次询问数列每次询问数列第li个元素到ri个元素的和。

        核心代码:ans=sum[ri]-sum[li-1];        //sum[i]存前i个数的和

差分 

        为进一步引申出差分再举一个例子:

例2

        每个同学都知道自己的分数比前一人多多少分,告诉你第一个人的分数,求每个人的分数。第x个同学记性不好,算错了他和前一个人的差值(但其他同学没算错),现在将他和第一个同学的差值改为y,求每个同学的分数。

         上述例子可以抽象化为一个数列修改问题:给一个数列{an},有q次修改,每次将数列中第li到ri的每个元素都加上一个值ki,求所有修改后每个数的值。

        通过上述前缀和的思想,我们思考是否可以通过维护一个量,保证可以通过操作区间端点达到目的,即维护的量可以保证在修改时区间内部量不变,区间端点量改变。易得,此量即是差值。举例来具体说明:

        令a[i]是第i名同学与其前面同学的分数差值,假设第1到4名同学与之前同学的分数之差分别为a[1]=88(作为第一名同学所以分数设大点), a[2]=1, a[3]=3, a[4]=-1,a[5]=4,则易得第1到4名同学的分数为88、89、92、91、95。

        这时若发现第二名同学记错了,其实他自己比前一名同学多了5分,少算了4分!我们仅修改区间端点:a[2]=5。可以发现,此时后方同学再计算(前一名同学的分数+自己与前一名同学的分数差)时,就自动加上了这4分。

        区间修改也是一样的,但是对所给区间加减值,而不是像上述修改分数一样,之后的所有分数都要变化。那操作区间右方的值多加了怎么办?很简单,再减去之前多加的就好了。还是拿上面的例子说明,假设只有区间[2,3]上的值需要多加4,那么对于a[2]同样使它的值为5,使得第2、3名同学的分数变为93、 96。既然前面的改好了,只要让a[4]减去多加的就行啦,即让a[4]=-5。再计算第4、 5名同学的分数,发现为91、95没变。

        总结:设delta[i]维护第i个数与前一个数的差值,则修改区间[l,r]的值使其加x,可以通过使delta[l]+x、delta[r+1]-x来维护区间内的数值。而用数组delta[i]来维护第i个数和前一个数的差值的办法叫做差分。上面例子中的a[i]其实就是差分数组。

两者的关系

        可以发现差分和前缀和是一对对称的操作:对差分数组求前缀和就是原数组(分数差求前缀和就是原来的分数),对前缀和求差分也会得到原数组(对大于等于x分的人数求差分会得到原来x分数下的人数)。

        令sum为前缀和数组,a为原数组,delta为差分数组,为了好理解不妨就解释sum为考试分数大于等于x的人数,a为等于x的人数,delta为等于x的人数与等于x-1人数的差值,则:

        

sum[i]=a[i]+sum[i-1];    // 大于等于i分的人数=i分的人数+大于等于i-1分的人数

a[i]=sum[i]-sum[i-1];    // i分的人数=大于等于i分的人数-大于等于i-1分的人数

delta[i]=a[i]-a[i-1];    // i分的人数与i-1分的人数的差值=i分的人数 - i-1分的人数

a[i]=delta[i]+a[i-1];    //i分的人数=i分的人数与i-1分的人数的差值 + i-1分的人数

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值