树状数组区间操作模板

推荐一篇博客:
http://m.blog.csdn.net/blackjack_/article/details/74997479
推导过程在代码之前,模板题是Luogu 3368或者codevs线段树练习3

/*
    pre_sum(n)=a[1]+a[2]+...+a[n]
            =c[1]+(c[1]+c[2])+...+(c[1]+c[2]+...+c[n])
            =n*(c[1]+c[2]+...+c[n])-(0*c[1]+1*c[2]+...+(n-1)*c[n])
    令d[i]=(i-1)*c[i]
    modify(l,r,+v):
        add(c,l,v),add(c,r+1,-v),add(d,l,(l-1)*v),add(d,r+1,-r*v)
    pre_sum(n)=n*query(c,n)-query(d,n)
    sum(l,r)=pre_sum(r)-pre_sum(l-1)
*/
#include
using namespace std;
const int MAXN=5e5+2;
int n,m,c[MAXN],d[MAXN];
inline int read() {
    int x=0,f=1;char c=getchar();
    while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
    while (c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
    return x*f;
}
inline void add(int *r,int pos,int v) {
    for (int i=pos;i<=n;i+=(i&-i))
        r[i]+=v;
}
inline int query(int *r,int pos) {
    int ret=0;
    for (int i=pos;i;i-=(i&-i))
        ret+=r[i];
    return ret;
}
int main() {
//  freopen("P3368.in","r",stdin);
    memset(c,0,sizeof(c)),
    memset(d,0,sizeof(d));
    n=read(),m=read();
    for (register int i=1;i<=n;++i) {
        int v=read();
        add(c,i,v),add(c,i+1,-v),add(d,i,(i-1)*v),add(d,(i+1),-i*v);
    }
    for (register int i=1;i<=m;++i) {
        int opt=read();
        if (opt&1) {
            int l=read(),r=read(),v=read();
            add(c,l,v),add(c,r+1,-v),add(d,l,(l-1)*v),add(d,(r+1),-r*v);
        }
        else {
            int pos=read(),l=pos-1,r=pos;
            int t1=r*query(c,r)-query(d,r),t2=l*query(c,l)-query(d,l);
            printf("%d\n",t1-t2);
        }
    }
    return 0;
}

你可能感兴趣的:(OI-模板,树状数组)