树状数组维护区间加减与查询

NOIP ,发条题解增加rp;

树状数组维护区间和。

令 原数组为a i a1 i为 ai 到 an的共同增量,

那么 我们要求区间和 等价于求 1到x的和 (可以ask r-ask(l-1));

ask x =a1+a2+..ax+x*a1 1+(x-1)*a1 2+..a1 x

    =a1+a2+..ax+(x+1)*(a1 1+a1 2+a1 3+...a1 x)-1*a1 1-2*a1 2-3*a1 3...x*a1 x

那么我们维护 a1 和 i*a1 的数组即可

下附代码

#include<bits/stdc++.h>
#define sight(c) ('0'<=c&&c<='9')
#define LL long long
#define gc getchar
#define getchar nc
#define L(x) (x&-x)
#define N 100007
using namespace std;
LL a[N],a1[N],a2[N],x,y,k,op,n,m;
inline char nc(){
    static char buf[1000000],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++;
}
inline void read(LL &x){
    static char c;
    for(c=gc();!sight(c);c=gc());
    for(x=0;sight(c);c=gc()) x=x*10+c-48;
}
void write(LL x){if (x<10) {putchar('0'+x);return;}write(x/10); putchar('0'+x%10);}
inline void change(LL *A,int x,int dla) {for (;x<N;x+=L(x)) A[x]+=dla;}
inline LL add(LL *A,int x){LL O=0;for(;x;x-=L(x)) O+=A[x];return O;}
inline LL ask(int r){return a[r]+(r+1)*add(a1,r)-add(a2,r);}
int main () {
    read(n); read(m);
    for (int i=1;i<=n;i++) read(x),a[i]=a[i-1]+x;
    while (m--) {
        read(op);
        if (op&1) {
            read(x); read(y); read(k);
            change(a1,x,k); change(a1,y+1,-k);
            change(a2,x,k*x); change(a2,y+1,-k*(y+1));
        } else {
            read(x); read(y);
            write(ask(y)-ask(x-1)); putchar('\n');
        }
    }
    return 0;
}

  

posted @ 2017-12-01 20:25  泪寒之雪  阅读(188)  评论(0编辑  收藏  举报