树状数组的区间查询区间加

题目:

已知一个数列,你需要进行下面两种操作:

1.将某区间每一个数加上x

2.求出某区间每一个数的和


考虑在用树状数组区间查询,单点修改时我们做了什么

我们用了一个差分数组(b[i]),则(sum_{i=1}^x b[i])即是对(a[x])的贡献

如果我们考虑(b)数组对(a)的前缀和的贡献

(b)(sum_{i=1}^x a[i])的贡献

(sum_{i=1}^x sum_{j=1}^i b[j])

化简它
(sum_{i=1}^x (x+1-i) imes b[i])
(=(x+1)sum_{i=1}^x b[i]-sum_{i=1}^x i imes b[i])

我们用两个树状数组分别维护这两项即可


Code:

#include <cstdio>
#define ll long long
const int N=100010;
ll c[2][N],s[N];
int n,m;
void add(int typ,int x,ll delta)
{
    while(x<=n)
    {
        c[typ][x]+=delta;
        x+=x&-x;
    }
}
ll query(int typ,int x)
{
    ll ans=0;
    while(x)
    {
        ans+=c[typ][x];
        x-=x&-x;
    }
    return ans;
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        scanf("%lld",s+i);
        s[i]+=s[i-1];
    }
    int opt,x,y;ll k;
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d%d",&opt,&x,&y);
        if(opt==1)
        {
            scanf("%lld",&k);
            add(0,x,k),add(0,y+1,-k);
            add(1,x,k*x),add(1,y+1,-k*(y+1));
        }
        else
            printf("%lld
",s[y]+(y+1)*query(0,y)-query(1,y)-(s[x-1]+x*query(0,x-1)-query(1,x-1)));
    }
    return 0;
}

2018.7.26

原文地址:https://www.cnblogs.com/butterflydew/p/9370363.html