zoukankan      html  css  js  c++  java
  • 树状数组的区间查询区间加

    题目:

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

    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

  • 相关阅读:
    不同的ospf进程发布互联网段可以互通
    大数分解
    主席树(非权值)
    块状数组
    Codeforces Round #744 (Div. 3) G. Minimal Coverage
    记录一种从天而降的掌法(动态维护中位数的方法)
    快速统计二进制中1的数量
    网络流(小常数)
    矩阵快速幂
    米勒罗宾素性检验
  • 原文地址:https://www.cnblogs.com/butterflydew/p/9370363.html
Copyright © 2011-2022 走看看