【树状数组】区间修改、区间查询

其实呢,树状数组最有价值的是如何区间修改、区间查询,因为不会,我之前一度用分块, 学会树状数组区间修改、区间查询非常重要

当你点开这篇文章时,说明你是一个有志向的人。毕竟,多数人都看不好它

废话到此为止,进入正题

那么如何进行树状数组区间修改、区间查询呢 (还是句废话)

先想到差分
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,x2x1,x3x2,,xnxn1}
设查询区间 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=lrxi=i=lrj=1idj
会发现有 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)={rl+1,ri+1,i<llir
原式 = ( 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} 原式=(rl+1)i=1l1di+i=lr(ri+1)×di=(r+1)i=1l1dili=1l1di+(r+1)i=lrdii=lrdii=(r+1)i=1rdili=1l1dii=lrdii=(r+1)i=1rdili=1l1dii=1rdii+i=1l1dii
似乎越来越复杂了,但这样,我们就能分两个树状数组分别维护 ∑ i = 1 x d i ( t a 1 ) \sum_{i=1}^{x}d_i(ta1) i=1xdi(ta1) ∑ i = 1 x d i ∗ i ( t a 2 ) \sum_{i=1}^{x}d_i*i(ta2) i=1xdii(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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值