树状数组的区间修改与区间查修


考虑差分
sum[i] = a[1]+...+a[i] + delta[1]*i + delta[2]*(i-1)+delta[3]*(i-2)+...+delta[i]*1 // a[i]为原始数组
= sigma(a[x])+sigma(delta[x]*(i+1-x))
= sigma(a[x])+(i+1)*sigma(delta[x])-sigma(delta[x]*x)
所以我们记sum为前缀和,delta[i],deltai[i]=delta[i]*i

//sum[i] = a[1]+...+a[i] + delta[1]*i + delta[2]*(i - 1) + delta[3]*(i - 2)+...+delta[i]*1   // a[i]为原始数组  
    //= sigma( a[x] ) + sigma( delta[x]  *  (i + 1 - x) )  
    //= sigma( a[x] ) + (i + 1) * sigma( delta[x] ) - sigma( delta[x] * x )  
#include<bits/stdc++.h>
using namespace std;
const int N=200100;
int n;
long long sum[N];//原始数组前缀和 
long long delta[N];//差分数组 
long long deltai[N];//delta[x]*i 
inline int lowbit(int x) {return x&(-x);}
void add(long long *c,int a,int b)
{
    while(a<=n)
    {
        c[a]+=b;
        a+=lowbit(a);
    }
}
long long query(long long *c,int a)
{
    long long s=0;
    while(a) 
    {
        s+=c[a];
        a-=lowbit(a);
    }
    return s;
}

int main()
{
    freopen("a.in","r",stdin);
    scanf("%d",&n);
    int a;
    for(int i=1;i<=n;i++) scanf("%d",&a),sum[i]=sum[i-1]+a;
    int m,l,r,x;
    scanf("%d",&m);
    long long suml,sumr;
    for(int i=1;i<=m;i++) 
    {
        scanf("%d",&a);
        if(a==1)
        {
            scanf("%d%d%d",&l,&r,&x);
            add(delta,l,x);add(delta,r+1,-x);
            add(deltai,l,x*l);add(deltai,r+1,-x*(r+1));
        }
        else 
        {
            scanf("%d%d",&l,&r);
            suml=sum[l-1]+l*query(delta,l-1)-query(deltai,l-1);
            sumr=sum[r]+(r+1)*query(delta,r)-query(deltai,r);
            printf("%lld
",sumr-suml);
        }
    }
    
    return 0;
}

原文地址:https://www.cnblogs.com/Heey/p/9039113.html