其实呢,树状数组最有价值的是如何区间修改、区间查询,因为不会,我之前一度用分块, 学会树状数组区间修改、区间查询非常重要
当你点开这篇文章时,说明你是一个有志向的人。毕竟,多数人都看不好它
废话到此为止,进入正题
先想到差分
记 x i x_i xi 为原数组, d i d_i di 为差分数组,数组长度为 n n n
则有 d = { x 1 , x 2 − x 1 , x 3 − x 2 , ⋯ , x n − x n − 1 } d=\{x_1,x_2-x_1,x_3-x_2,\cdots,x_n-x_{n-1}\} d={x1,x2−x1,x3−x2,⋯,xn−xn−1}
设查询区间 l , r l,r l,r
解:
∑ i = l r x i = ∑ i = l r ∑ j = 1 i d j \sum_{i=l}^{r} x_i=\sum_{i=l}^{r}\sum_{j=1}^{i} d_j i=l∑rxi=i=l∑rj=1∑idj
会发现有 d i d_i di 是重复出现的,进行归纳总结
出现次数
c ( i ) = { r − l + 1 , i < l r − i + 1 , l ≤ i ≤ r c(i) = \begin{cases} r-l+1, & i < l \\ r-i+1, & l\le i \le r \end{cases} c(i)={r−l+1,r−i+1,i<ll≤i≤r
原式 = ( r − l + 1 ) ∑ i = 1 l − 1 d i + ∑ i = l r ( r − i + 1 ) × d i = ( r + 1 ) ∑ i = 1 l − 1 d i − l ∑ i = 1 l − 1 d i + ( r + 1 ) ∑ i = l r d i − ∑ i = l r d i ∗ i = ( r + 1 ) ∑ i = 1 r d i − l ∑ i = 1 l − 1 d i − ∑ i = l r d i ∗ i = ( r + 1 ) ∑ i = 1 r d i − l ∑ i = 1 l − 1 d i − ∑ i = 1 r d i ∗ i + ∑ i = 1 l − 1 d i ∗ i \begin{aligned} \texttt{原式}&=(r-l+1)\sum_{i=1}^{l-1}d_i+\sum_{i=l}^{r}(r-i+1)\times d_i\\ &=(r+1)\sum_{i=1}^{l-1}d_i-l\sum_{i=1}^{l-1}d_i+(r+1)\sum_{i=l}^{r}d_i-\sum_{i=l}^{r}d_i*i\\ &=(r+1)\sum_{i=1}^{r}d_i-l\sum_{i=1}^{l-1}d_i-\sum_{i=l}^{r}d_i*i\\ &=(r+1)\sum_{i=1}^{r}d_i-l\sum_{i=1}^{l-1}d_i-\sum_{i=1}^{r}d_i*i+\sum_{i=1}^{l-1}d_i*i \end{aligned} 原式=(r−l+1)i=1∑l−1di+i=l∑r(r−i+1)×di=(r+1)i=1∑l−1di−li=1∑l−1di+(r+1)i=l∑rdi−i=l∑rdi∗i=(r+1)i=1∑rdi−li=1∑l−1di−i=l∑rdi∗i=(r+1)i=1∑rdi−li=1∑l−1di−i=1∑rdi∗i+i=1∑l−1di∗i
似乎越来越复杂了,但这样,我们就能分两个树状数组分别维护 ∑ i = 1 x d i ( t a 1 ) \sum_{i=1}^{x}d_i(ta1) i=1∑xdi(ta1)与 ∑ i = 1 x d i ∗ i ( t a 2 ) \sum_{i=1}^{x}d_i*i(ta2) i=1∑xdi∗i(ta2)
void upt(int l,int r,int x){
up(l,x,ta1);
up(r+1,-x,ta1);
up(l,x*l,ta2);
up(r+1,-x*(r+1),ta2);
}
void quy(int l,int r){
int s1=(r+1)*qy(r,ta1)-l*qy(l-1,ta1);
int s2=qy(r,ta2)-qy(l-1,ta2);
return s2-s1;
}
还是挺好写的
int ta1[N],ta2[N];
#define lowbit(x) ((-x)&x)
void up(int u,int x,int ta[N]){
for(int i=u;i<N;i+=lowbit(i))
ta[i]+=x;
}
int qy(int u,int ta[N]){
int ans=0;
for(int i=u;i;i-=lowbit(i))
ans+=ta[i];
return ans;
}
void upt(int l,int r,int x){
up(l,x,ta1);
up(r+1,-x,ta1);
up(l,x*l,ta2);
up(r+1,-x*(r+1),ta2);
}
void quy(int l,int r){
int s1=(r+1)*qy(r,ta1)-l*qy(l-1,ta1);
int s2=qy(r,ta2)-qy(l-1,ta2);
return s2-s1;
}