poj 3468 树状数组 区间更新 区间求和

poj 3468




/*
树状数组区间更新,区间求和
利用两个树状数组进行实现
原理

先讲:通过树状数组的区间更新,单点查询我们知道
对一个点i的更新值为sum(c[1...i])+a[i] a[]为初始数据,c[]为树状数组的值
那么对于区间[l,r]
则为:SUM = sum[a[l...r]]+sum[sum(c[1...l])...sum(c[1...r])]
                   A     +   B
A部分用前缀和
B部分
B = c[1]+c[1...2]+c[1...3]+...+c[1...r] - (c[1]+c[1...2]+c[1...3]+...+c[1...r])
                C                       -          D
C 和D一个形式
C = r*c[1]+(r-1)*c[2]+...+c[r]
  = (r+1)*sum(c[1...r]) - (1*c[1]+2*c[2]+...+r*c[r])
  = (r+1)*sum(c[1...r]) - sum(i*c[1..r])
所以
SUM = sum[a[1...r]] - sum[a[1...l]]+(r+1)*sum(c[1...r]) - sum(i*c[1..r]) - ((l+1)*sum(c[1...l]) - sum(i*c[1..l]))
用前缀和处理a[]用树状数组处理c[]和i*c[]两个数组
*/
#include<cstdio>
#include<algorithm>
using namespace std;
#define XINF INT_MAX
#define INF 0x3FFFFFFF
#define mp(X,Y) make_pair(X,Y)
#define pb(X) push_back(X)
#define rep(X,N) for(int X=0;X<N;X++)
#define rep2(X,L,R) for(int X=L;X<=R;X++)
#define dep(X,R,L) for(int X=R;X>=L;X--)
#define clr(A,X) memset(A,X,sizeof(A))
#define it iterator
#define lson l,m,((rt)<<1)
#define rson m+1,r,((rt)<<1|1)
#define in(x) scanf("%d",&x)
#define in2(x,y) scanf("%d%d",&x,&y)
#define in3(x,y,z) scanf("%d%d%d",&x,&y,&z)
#define out1(x)  printf("%d\n",x)
typedef long long ll;
const int maxn = 100005;
int lb(int i){return (-i)&i;}
template<typename X>
struct tree_arr{
    X bits[maxn];
    int n;
    void init(int s){n = s;rep2(i,1,s)bits[i] = 0;}
    void add(int i,X y){while(i<=n){bits[i]+=y;i+=lb(i);}}
    X query(int i){X s = 0;while(i>0){s+=bits[i];i-=lb(i);}return s;}
};
tree_arr<ll> d,di;
ll sum[maxn];
int main(){
    int n,q;
    while(in2(n,q)!= EOF){
        d.init(n);
        di.init(n);
        rep(i,n+1)sum[i] = 0;
        rep2(i,1,n){
            ll a;scanf("%I64d",&a);
            sum[i]+=sum[i-1]+a;
        }
        while(q--){
            char op[20];
            int x,y,z;
            scanf("%s",op);
            if(op[0] == 'Q'){
                in2(x,y);
                ll ans = 0;
                ans+=sum[y] - sum[x-1];
                ans+=(y+1)*d.query(y) - x*d.query(x-1);
                ans-=di.query(y) - di.query(x-1);
                printf("%I64d\n",ans);
            }
            else{
                in3(x,y,z);
                d.add(x,z);d.add(y+1,-z);
                di.add(x,x*z);di.add(y+1,(y+1)*(-z));
            }
        }
    }

}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值