树状数组(区间修改,区间查询 )

首先还是先利用区间修改 单点查询用过的差分思想(将区间的修改操作变成单点的修改),我们先搞一个c数组作为差分数组

  a数组是原数组,c数组是差分数组。

简单可证:

a[1] = c[1] ,  a[2] = c[2] + c[1],  a[3] = c[3] + c[2] + c[1],……;

那么可以得到以下式子:

a[1]+a[2]+...+a[i]

=c[1] + ( c[1] + c[2] ) + ... + ( c[1] + c[2] + ... + c[i] )

=i*c[1]+(i-1)*c[2]+...+c[i]

=i *(c[1]+c[2]+...+c[i])-1*c[2]-...-(i-1)*c[i]

于是,我们再搞一个数组d=(i-1)*c[i]

那之前的式子就可以表示为

a[1]+a[2]+…+a[i]=i*(c[1]+c[2]+...+c[i])-(d[1]+d[2]+...+d[i]);

 

#include<iostream>
#include<cstdio> 
using namespace std;

long long n,m;
long long a[500009]; 
long long c[500009],d[500009];
long long lowbit(long long x)
{
    return (x&(-x));
}
void change(long long *e,long long x,long long k)
{
    for(int i=x;i<=n;i+=lowbit(i))
    {
        e[i]+=k;
    }
}
long long query(long long *e,long long x)
{
    long long sum=0;
    for(int i=x;i>=1;i-=lowbit(i))
    {
        sum+=e[i];
    }
    return sum;
}
inline long long read()
{
    long long x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    return x*f;
}
int main()
{
    n=read(),m=read();
    for(int i=1;i<=n;i++)
    {
        a[i]=read();
        change(c,i,a[i]-a[i-1]);
        change(d,i,(long long)(i-1)*(a[i]-a[i-1]));
    }
    for(int i=1;i<=m;i++)
    {
        long long p;
        cin>>p;
        if(p==1)//修改 
        {
            long long r,l,v;
            cin>>l>>r>>v;
            change(c,l,v);
            change(c,r+1,-v);
            change(d,l,(long long)(l-1)*v);
            change(d,r+1,(long long)-r*v);
        }
        if(p==2)//统计 
        {
            long long r,l;
            cin>>l>>r;
            long long t1=query(c,l-1)*(l-1)-query(d,l-1);
            long long t2=query(c,r)*r-query(d,r);
            printf("%lld\n",t2-t1);
        }
    }
    return 0;
}
/*
5 2
1 7 6 5 8
1 2 3 1//修改【2~3】+1 
2 2 4//查询2~4 
*/

 

posted @ 2019-07-21 15:26  nono_ttaa  阅读(165)  评论(0编辑  收藏  举报