【模板】树状数组的区间加值和区间查询

来源:互联网 发布:海量数据存储算法 编辑:程序博客网 时间:2024/06/11 10:33

树状数组可以实现单点修改区间查询,或是差分的区间修改单点查询。【点这里】
那么树状数组能不能实现区间加值区间查询呢?
原始序列为a[]。我们先考虑区间加值,用差分的方式维护一个d[]数组,d[x]表示的是[x,maxn]每个数的增量。
那么如果需要查询1~x的前缀和,需要查的是
sumx=sigmaai+d1x+d2(x1)+d3(x2)+...+dx1
=sigma(ai)+sigma(di(x+1i))
=sigma(ai)+(x+1)sigma(di)sigma(dii)
所以把di处理一个树状数组tree[],dii处理成一个树状数组treex[]。查询sum[x]时只需要求suma[x]+(x+1)*tree[x]-treex[x]就可以了。
模板题是【模板】线段树1 洛谷P3372

#include<bits/stdc++.h>#define lowbit(x) (x&(-x))using namespace std;int n,m;long long a[100005];long long tree[100005],treex[100005];inline void add(long long *ths,int x,long long num){    while(x<=n){        ths[x]+=num;        x+=lowbit(x);    }}inline long long search(long long *ths,int x){    long long re=0;    while(x){        re+=ths[x];        x-=lowbit(x);    }    return re;}inline long long search(int x){    return a[x]+(x+1)*search(tree,x)-search(treex,x);}int main(){    scanf("%d%d",&n,&m);    for(int i=1;i<=n;++i)   scanf("%lld",&a[i]),a[i]+=a[i-1];    while(m--){        int opt;        scanf("%d",&opt);        if(opt==1){            int l,r;            long long k;            scanf("%d%d%lld",&l,&r,&k);            add(tree,l,k);   add(tree,r+1,-k);            add(treex,l,l*k);add(treex,r+1,-(r+1)*k);        }        else{            int l,r;            scanf("%d%d",&l,&r);            printf("%lld\n",search(r)-search(l-1));        }    }    return 0;}
阅读全文
0 0
原创粉丝点击