树状数组同理。再考虑单点查询。因为差分之后树状数组所求得的前缀和,也是差分数组的前缀和,恰好对应了需要查询的单点值,所以只需要在添加的时候不直接增加a[i],而是增加a[i]-a[i-1]。
参考代码
差分+公式理解了上面的差分树状数组,接下来还有更毒瘤的哦~
在上面的两个操作中,我们实际进行的操作都是一个单点+一个区间,两个操作都是单点就不用说了,如果两个操作都是要求在一个区间完成呢?
也就是说,我们的树状数组又要实现这两个功能:
1.区间修改
2.区间查询
首先,为了照样完成区间修改操作,差分的思想我们必须保留,否则挨个修改会使时间复杂度爆棚。
那么我们要怎么在差分的情况下完成区间查询呢?
我们先来分析一下问题。区间查询,本质上是求原本的a[]的前缀和。但是因为每一个a[]中的值都是以差分b[]的形式存储的,所以每一个a[]的值我们都要用一次\(\sum_{i=1}^x b[i]\)来求得,但是我们要求的是前缀和,所以我们每次查询要求的是这样一个玩意:
\(\sum_{i=1}^x \sum_{j=1}^i b[i]\)
我们发现,对于每一个b[i],它被累加的次数是一定的,这个时候用循环累加就很浪费时间。观察一下,每个\(b[i]\)在这个过程中,会被累加\((x-i+1)\)次。看下面的图形就知道了。
b1 b1 b2 b1 b2 b3 b1 b2 b3 b4 ... b1 b2 b3 b4 b5 ... bx于是我们的公式就可以变形成\(\sum_{i=1}^x (x-i+1)*b[i]\)。
再从括号里把-i项提取出来,得到\(\sum_{i=1}^x (x+1)*b[i] - \sum_{i=1}^x b[i]*i\)
于是,就变成了维护两个差分树状数组的问题了。