树状数组使用总结 树状数组使用总结 1.区间修改+单点查询(一维) 2.区间修改+区间查询(一维) 3.单点修改+区间查询(二维) 4.区间修改+单点查询(二维) 5.区间修改+区间查询(二维)

在考试中 因为不清楚二维树状数组怎么用 而失手了无数遍了...
今天终于把这个坑填了.... =_=

1.区间修改+单点查询(一维)

把查询第(x)个位置的值(s_x)变为查询前缀和(s_x = sum_{i = 1}^x d(i))
其中 (d(x) = s_x - s_{x-1})
修改([L,R])的时侯,只需要修改 (L)(R)+(1) 两个点。

2.区间修改+区间查询(一维)

查询([1,x]),则有:

[res = sum_{i=1}^x s_x = sum_{i = 1}^x sum_{j = 1}^i d(j) ]

[sum_{i = 1}^x sum_{j = 1}^i d(j) = sum_{j = 1}^x d(j)(x - j + 1) = (x+1)sum_{j = 1}^x d(j) - sum_{j = 1}^x d(j)j ]

所以用两个树状数组分别维护(sum d(i))(sum d(i)*i)即可。

3.单点修改+区间查询(二维)

直接维护((1,1))((x,y))的这个矩阵的和即可。 代码类似一维处理即可:

for( x ; x <= n ; x += lowbit(x) )
    for( y ; y <= m ; y += lowbit(y) )updata or query

查询时用一下二维前缀和容斥一下就行了。

4.区间修改+单点查询(二维)

一样的转为差分值:(s_{{x,y}} = sum_{i = 1}^x sum_{j=1}^y d(i,j))
其中$d(i,j) = s_{{x,y}} - s_{{x-1,y}} - s_{{x,y-1}} + s_{{x-1,y-1}} ( 修改时只修改)(x_1,y_1)(、)(x_1,y_2+1)(、)(x_2+1,y_1)(、)(x_2+1,y_2+1)$
查询时一样的用 单点修改+区间查询(二维) 的方法查询。

5.区间修改+区间查询(二维)

[res = sum_{i=1}^x sum_{j=1}^y sum_{k=1}^i sum_{h=1}^j d(k,h) ]

把后面两个(sum)提到前面来:

[res = sum_{i=1}^x sum_{j=1}^y d(i,j)(x-i+1)(y-j+1) ]

展开后得到:
$res = res $

$+(x+1)(y+1) [ sum_{i=1}^x sum_{j=1}^y d(i,j) ] ( )- (x+1) [ sum_{i=1}^x sum_{j=1}^y d(i,j)j ]( )- (y+1)* [ sum_{i=1}^x sum_{j=1}^y d(i,j)i ]( )+ [ sum_{i=1}^x sum_{j=1}^y d(i,j)ij ]( 所以用四个树状数组分别维护)sum d()$ , (sum d()i) , (sum d()j) , (sum d()ij) 即可 , 具体实现戳这里