[学习笔记] 树状数组区间加+区间求和

  • bi=aiai1,ci=(i1)×bi b i = a i − a i − 1 , c i = ( i − 1 ) × b i ,则:
    i=1nai ∑ i = 1 n a i
    =a1+a2++an = a 1 + a 2 + … + a n
    =i=11bi+i=12bi++i=1nbi = ∑ i = 1 1 b i + ∑ i = 1 2 b i + … + ∑ i = 1 n b i
    =n×i=1nbii=1n(i1)×bi = n × ∑ i = 1 n b i − ∑ i = 1 n ( i − 1 ) × b i
    =n×i=1nbii=1nci = n × ∑ i = 1 n b i − ∑ i = 1 n c i
  • 我们用两个树状数组分别维护 bi,ci b i , c i
    1.令区间 [l,r] [ l , r ] 加上 x x ,即为
    bl+=x,br+1=x b l + = x , b r + 1 − = x
    cl+=(l1)×x,cr+1=r×x c l + = ( l − 1 ) × x , c r + 1 − = r × x

    2.询问区间 [l,r] [ l , r ] 的和,即为
    r×i=1rbii=1rci(l1)×i=1l1bi+i=1l1ci r × ∑ i = 1 r b i − ∑ i = 1 r c i − ( l − 1 ) × ∑ i = 1 l − 1 b i + ∑ i = 1 l − 1 c i
  • 代码
const int N = 1e5 + 5;
ll b[N], c[N]; int a[N], n, m;

inline void Modify(ll *s, int x, ll y)
{
    for (; x <= n; x += x & -x)
        s[x] += y;
}

inline ll Query(ll *s, int x)
{
    ll res = 0;
    for (; x; x ^= x & -x)
        res += s[x];
    return res;
}

int main()
{
    n = get(); m = get(); int k, l, r, x;
    for (int i = 1; i <= n; ++i)
    {
        a[i] = get();
        Modify(b, i, a[i] - a[i - 1]);
        Modify(c, i, 1ll * (i - 1) * (a[i] - a[i - 1]));
    }

    while (m--)
    {
        k = get(); l = get(); r = get();
        if (k & 1)
        {
            x = get();
            Modify(b, l, x); 
            Modify(b, r + 1, -x);
            Modify(c, l, 1ll * (l - 1) * x);
            Modify(c, r + 1, -1ll * r * x); 
        }
        else 
        {
            --l;
            put(Query(b, r) * r - Query(c, r)
              - Query(b, l) * l + Query(c, l));
            putchar('\n'); 
        }
    }
}

你可能感兴趣的:(学习笔记,树状数组,模板,数学)