树状数组改段求段

如何运用树状数组进行区间操作

先定义两个树状数组 X, Y

现在我们需要对一个数组 int a[N]; 进行区间操作:[L, R] += val 即 for i:L to R a[i] += val; 

再定义一个 int size = R-L+1 , 即区间长度

对应的修改是 

1、X[L] += val;   X[R+1] -= val;

2、Y[L] += -1 * val * (L-1);   Y[R+1] += val * R;

对应的查询是

当我们求和  时在树状数组中操作是 ans = X.sum(k) * k + Y.sum(k)

分类讨论一下k分别在 [1,L-1] , [L, R] , [R+1, +]

1、k[1,L-1]  

显然 X.sum(k) == 0 且 Y.sum(k) == 0 -> ans = X.sum(k)*k + Y.sum(k) = 0*i+0 = 0 结果与实际相符。

2、k[L, R] 

X.sum(k) * k = X[L] * k = val * k,   Y.sum(k) = Y[L] =  -1 * val * (L-1) 

ans = val * k - val * (L-1) = val * ( k - (L-1) ); 

3、k[R+1, ]

X.sum(k) * k = ( x[L] + x[R] ) * k = 0 * k = 0;

Y.sum(k) = Y[L] + Y[R] = -val * (L-1) + val * R = val * (R-L+1) = val * size

X.sum(k) * k + Y.sum(k) = val * size

证毕

以下模版中两个树状数组c[0], c[1] 对应上述的X, Y

区间修改:add(L, R, val)

求 int a[N]的前缀和 get_pre(R)

区间查询:get(L,R)

const int N = 4e5 + 100;  
template<class T>  
struct Tree{  
    T c[2][N];  
    int maxn;  
    void init(int x){  
        maxn = x+10; memset(c, 0, sizeof c);  
    }  
    inline int lowbit(int x){ return x&-x; }  
    T sum(T *b, int x){  
        T ans = 0;  
        if (x == 0)ans = b[0];  
        while (x)ans += b[x], x -= lowbit(x);  
        return ans;  
    }  
    void change(T *b, int x, T value){  
        if (x == 0)b[x] += value, x++;  
        while (x <= maxn)b[x] += value, x += lowbit(x);  
    }  
    T get_pre(int r){  
        return sum(c[0], r) * r + sum(c[1], r);  
    }  
    void add(int l, int r, T value){//区间加权  
        change(c[0], l, value);  
        change(c[0], r + 1, -value);  
        change(c[1], l, value * (-l + 1));  
        change(c[1], r + 1, value * r);  
    }  
    T get(int l, int r){//区间求和  
        return get_pre(r) - get_pre(l - 1);  
    }  
};  
Tree<ll> tree;  
转载自:http://blog.csdn.net/qq574857122/article/details/46876877

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值