樹狀數組的區間修改問題

我昨天寫樹狀數組的時候 最初建樹的時候是用的原值 沒有修改後的值
但是 這樣寫不能實現區間的加權 必須一個點一個點的更新 很麻煩
然後我百度了一下發現一開始建樹存的是數的差值
update(i,a[i] - a[i-1]);
我覺得可能是我的數學理論基礎不夠紮實 不太能懂 爲啥存插值可以很方便的通過update(x,k); update(y+1,-k);的形式實現
 

新樹狀數組算法

 

 

 我在紙上推到了一遍
首先需要弄明白的一個特性,如果按照差分的形式存儲,可以通過構建的新數列的∑(1-i)得到a[i]
換言之就是 差分的和(1-i)等同於a[i]這個原來的數
然後 思考 如果要求出原數列的n項和
∑a[i] = ∑       ∑c[j] 
1-n      j:1-n   j:1-i
那麼這邊就會有很多重複項
 

根絕這個式子 倒數第三行分解開來
把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);
查詢:就比較方便 利用二進制思想的樹狀數組 相當於快查 這個不受影響

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

#include <bits/stdc++.h>

using namespace std;
const int maxn = 1e5 + 10;
vector<int> vec; //原數列
vector<int> 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;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章