树状数组区间修改区间查询

树状数组区间修改区间查询


其实在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们!

posted @ 2017-09-19 22:55  菜狗xzz  阅读(225)  评论(0编辑  收藏  举报