$\mathrm{Main \ Idea}$
本文主要来讲解二维树状数组的一些用法以及例题讲解。
$\mathrm{Problem’s \ Website}$
$\mathrm{T1}$:二维树状数组1:单点修改,区间求和($\mathbb{LOJ}$)
$\mathrm{T2}$:二维树状数组3:区间修改,区间求和($\mathbb{LOJ}$)
$\mathrm{T3}$:上帝造题的七分钟(洛谷)
$\mathrm{Solution}$
我们按照操作的类型来说,必要时再解释例题。
1.基本概念
首先对于普通的一维树状数组,我之前有过粗略的介绍,不懂的同学可以先去学习一下。
那我们来说一下二维树状数组的定义,我们定义$ta[i][j]$为以$(i,j)$为右下角,且高度为$lowbit(i)$,宽度为$lowbit(j)$的矩阵的和。
感觉还是比较好理解的。。。
2.单点修改区间查询
这是二维树状数组最基础的操作。
单点修改类似于一维树状数组,只不过是双重循环而已,而查询类似于二维前缀和,例如,输出左上角为$(x1,y1)$,右下角为$(x2,y2)$矩阵的和,公式为$ans = ask(x2,y2) - ask(x2,y1-1) - ask(x1-1,y2) + ask(x1-1,y1-1)$
不懂的同学可以画个图模拟一下。
这也就是$\mathrm{T1}$的题解。
代码会放在最后面。
3.区间修改单点查询
还是类似于一维树状数组此种操作,差分,仿照着二维前缀和,我们现在令$ta[i][j]$为$a[i][j]$与$a[i-1][j] + a[i][j-1] - a[i-1][j-1]$的差,求值时,我们直接求前缀和即可,那么如何修改?
例如,我们要修改左上角为$(x1,y1)$,右下角为$(x2,y2)$的矩阵统一加上$num$,我们要在$(x1,y1)$加上$num$,因为它比$(x1-1,y1)\ (x1,y1-1)\ (x1-1,y1-1)$多了$num$,要在$(x2+1,y1)$减去$num$,因为它之前多加了一个$num$,同理,要在$(x1,y2+1)$减去$num$,最后要在$(x2+1,y2+1)$加上$num$,因为它多减了一个$num$,如果我这样描述还不懂,建议画图理解。
本种操作暂未例题。。。
代码会放在后面。
4.区间修改区间查询
这就是最终的操作了,根据上文,我们不难推出式子$ans=\sum\limits_{i=1}^{x}{\sum\limits_{j=1}^{y}{\sum\limits_{k=1}^{i}{\sum\limits_{l=1}^{j}{ta[k][l]}}}}$,怎么那么长啊。。。
我们来缩短一下,经过模拟发现,$ta[1][1]$被计算了$x \times y$次,$ta[1][2]$被计算了$x \times (y-1)$次,$ta[2][1]$被计算了$(x-1) \times y$次,所以我们可以推出$ta[i][j]$计算了$(x-i+1)\times(y-j+1)$次,于是式子就被化简成了$ans=\sum\limits_{i=1}^{x}{\sum\limits_{j=1}^{y}{ta[i][j]\times(x-i+1)\times(y-j+1)}}$,我们再把这个式子展开,得到$ans=\sum\limits_{i=1}^{x}{\sum\limits_{j=1}^{y}{ta[i][j]\times(x+1)\times(y+1)}}-\sum\limits_{i=1}^{x}{\sum\limits_{j=1}^{y}{ta[i][j]\times i \times(y+1)}}-\sum\limits_{i=1}^{x}{\sum\limits_{j=1}^{y}{ta[i][j]\times j \times (x+1)}} + \sum\limits_{i=1}^{x}{\sum\limits_{j=1}^{y}{ta[i][j] \times i \times j}}$
那么我们只需要开四个树状数组,即:$ta[i][j],ta[i][j]\times i,ta[i][j] \times j,ta[i][j] \times i \times j$
以上就是$\mathrm{T2}$和$\mathrm{T3}$的题解。
下面就是你们最期待的代码。
$\mathrm{Code}$
- $\mathrm{T1}$
1 | //Coded by Dy. |
- 区间修改单点查询
1 | //Coded by Dy. |
- $\mathrm{T2}$
1 | //Coded by Dy. |
- $\mathrm{T3}$
1 | //Coded by Dy. |
$\mathrm{rp++}$