树状数组的区间修改问题

我昨天写树状数组的时候 最初建树的时候是用的原值 没有修改后的值
但是 这样写不能实现区间的加权 必须一个点一个点的更新 很麻烦
然后我百度了一下发现一开始建树存的是数的差值
update(i,a[i] - a[i-1]);
我觉得可能是我的数学理论基础不够扎实 不太能懂 为啥存插值可以很方便的通过update(x,k); update(y+1,-k);的形式实现
 

新树状数组算法

 

 

树状数组的区间修改问题_第1张图片

 我在纸上推到了一遍
首先需要弄明白的一个特性,如果按照差分的形式存储,可以通过构建的新数列的∑(1-i)得到a[i]
换言之就是 差分的和(1-i)等同于a[i]这个原来的数
然后 思考 如果要求出原数列的n项和
∑a[i] = ∑       ∑c[j] 
1-n      j:1-n   j:1-i
那么这边就会有很多重复项
树状数组的区间修改问题_第2张图片 

根绝这个式子 倒数第三行分解开来
把c[i]和另外一个式子分开来 可以发现第二个式子 c[i]*(i-1)是一个新数 可以专门存它
思路理清楚之后 利用树状数组的特性可以快速求和 与修改
(并不是根据树状数组得到这个特定的表达式 树状数组只是一种用于优化的二进制思想框架
所以 大概可以分为这么几步:
初始化:
    update(i,a[i]-a[i-1]); //构造c[i]数列
    update(i,(c[i] = a[i]-a[i-1])*[i-1]); //对c[i]这个数列用树状数组构造
区间修改: x->y +k
    update(x,k); update(y+1,-k); //对于差分数列的修改依然是老样子
    update(x,k*(i-1)); update(y+1,-k*(i-1)); //对于差分数列的修改
原理:∑(c[i]+k)*(i-1) = ∑c[i]*(i-1) + ∑k*(i-1);
查询:就比较方便 利用二进制思想的树状数组 相当于快查 这个不受影响
树状数组的区间修改问题_第3张图片

//
// Created by admin on 2020/3/3.
//

#include 

using namespace std;
const int maxn = 1e5 + 10;
vector vec; //原数列
vector c,b;
inline int lowbit(int x){
    return x&(-x);
}
inline void init(){
    vec.resize(maxn);
    c.resize(maxn);
    b.resize(maxn);
}
inline void update(int i,int k){
    int t_i = i;

    while(i < maxn){
        c[i] += k;
        b[i] += (t_i -1) * k;
        i += lowbit(i);
    }
}
inline void range_modify(int x,int y,int k){
    update(x,k);
    update(y+1,-k);
}
inline int query(int x){
    int res = 0;
    int tx = x;
    while(x){
        res += tx*c[x] - b[x];
        x -= lowbit(x);
    }
    return res;
}
inline int  range_query(int x,int y){
    return query(y) - query(x-1);
}
int main(){
    init();
    int n,m;

    cin >> n >> m;

    for(int i = 1 ; i <= n ; ++i){
        cin >> vec[i];
        update(i,vec[i] - vec[i-1]);
    }

    for(int i = 0 ; i < m ; ++i){
        int os;
        cin >> os;
        if(os == 1){
            int x,y,k;

            cin >> x >> y >> k;
            range_modify(x,y,k);
        }else{
            int x,y;

            cin >> x >> y;
            range_query(x,y);
        }
    }

    return 0;
}

 

你可能感兴趣的:(洛谷,算法,树状数组)