树状数组区间修改区间查询
树状数组区间修改区间查询
其实在csdn老博客上写过了。然而那个实在太丑,不想搬过来。(其实是为了秀一波LaTeX公式)
首先,设\(C_i\)为\([i,n]\)区间的共同增量。
修改:
差分思想,修改\(l\)和\(r+1\).
查询:
原数组没多大用,前缀和搞定不管。
假定树状数组开始全为0
约定:\(sum[i,j]\)表示\([i,j]\)区间的和
强行推公式:
\(sum[i,i]=\sum_{j=1}^{i}C_i\)
上面显然。不懂的就可以走了。。。
普通树状数组查询用到了差分思想,即\(sum[l,r]=sum[1,r]-sum[1,l-1]\).下面就来试着求\(sum[1,r]\).
\(sum[1,r]\)
\(=\sum_{i=1}^{r}sum[i][i]\)
\(=\sum_{i=1}^{r}\sum_{j=1}^{i}C_i\)
\(=\sum_{i=1}^{r}C_i×(r-i+1)\)
\(=\sum_{i=1}^{r}C_i×(r+1)-\sum_{i=1}^{r}C_i×i\)
所以发现:只需要新维护一个树状数组存储\(C_i×i\)就行了。
这个在修改里一并实现。
Code
// It is made by XZZ
#include<cstdio>
#include<algorithm>
using namespace std;
#define rep(a,b,c) for(rg int a=b;a<=c;a++)
#define drep(a,b,c) for(rg int a=b;a>=c;a--)
#define erep(a,b) for(rg int a=fir[b];a;a=nxt[a])
#define il inline
#define rg register
#define vd void
typedef long long ll;
il ll gi(){
rg ll x=0;rg char ch=getchar();
while(ch<'0'||ch>'9')ch=getchar();
while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
return x;
}
#define maxn 1000010
#define lb(o) (o&-o)
int n,m;
ll S[maxn],C[maxn],Ci[maxn];
il vd add(ll*ar,int pos,ll num){while(pos<=n)ar[pos]+=num,pos+=lb(pos);}
il ll sum(ll*ar,int pos){ll ret=0;while(pos)ret+=ar[pos],pos-=lb(pos);return ret;}
il vd Updata(int l,int r,ll num){
add(C,l,num);if(r^n)add(C,r+1,-num);
add(Ci,l,num*l);if(r^n)add(Ci,r+1,-num*(r+1));
}
il ll Query(int r){return(r+1)*sum(C,r)-sum(Ci,r)+S[r];}
int main(){
n=gi(),m=gi();
rep(i,1,n)S[i]=gi()+S[i-1];
int x,y;
while(m--)
if(gi()==1)x=gi(),y=gi(),Updata(x,y,gi());
else x=gi(),y=gi(),printf("%lld\n",Query(y)-Query(x-1));
return 0;
}
大牛分站开氧气,80ms,暂时第3版
很快要被刷下去了
%烂打zkw的dalao们!
博主是蒟蒻,有问题请指出,谢谢!
本博客中博文均为原创,未经博主允许请勿随意转载,谢谢。
本博客中博文均为原创,未经博主允许请勿随意转载,谢谢。