其实呢,树状数组最有价值的是如何区间修改、区间查询,因为不会,我之前一度用分块, 学会树状数组区间修改、区间查询非常重要
当你点开这篇文章时,说明你是一个有志向的人。毕竟,多数人都看不好它
废话到此为止,进入正题
那么如何进行树状数组区间修改、区间查询呢 (还是句废话)
先想到差分
记
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)
u p d a t e update update代码:
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);
}
q u e r y query query代码:
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;
}