美文网首页线段树
P3368【模板】树状数组2

P3368【模板】树状数组2

作者: 六十年目裁判长亚玛萨那度 | 来源:发表于2019-04-08 23:06 被阅读0次

    树状数组
    输入一个数组,那么我们所建立的数组:

    1 (10) = 1(2)
    第一位(1在二进制下=1 二进制下的第一个1,1=1)的值为输入的数组的第一位往前的一位的和,也就是第一位。
    2(10) = 10(2) 
    第二位(2在二进制下=10 二进制下的第一个1,10=2)的值为输入的数组的第二位往前两位的和,第一位和第二位。
    3(10) = 11(2)
    第三位(3在二进制下=11 二进制下的第一个1,1=1)的值为输入的数组的第三位往前一位的和,也就是第三位。
    4(10) = 100(2)
    第四位的值(4在二进制下=100 二进制下的第一个1,100=4)的值为输入的数组的第四位往前四位的和,也就是第一位,第二位,第三位以及第四位。

    本题也是利用树状数组,不过在插入树状数组的时候插入值是一个差分值。
    这种思想很有趣。
    因为本题是修改连续区间的值,但是直接插入数组如:
    arr : 1 2 3 4 5
    val : 1 4 8 5 2
    差分值 : 1 3 4 -3 -3
    从1到4都加2的话,维护太慢了也太麻烦,如果是维护他们的当前项和前一项的差值 ,那么如:
    arr : 1 2 3 4 5
    val : 3 6 10 7 2
    差分值 : 3 3 4 -3 -5
    只是改变第一项和第4+1项
    我们会发现:差分值相加得到的值就是当前值

    #include <iostream>
    using namespace std;
    
    #define LBS(_a) ((_a) & -(_a))
    #define SIZE 5000005
    
    int n, m;
    int arr[SIZE];
    
    int sum(int i) {
        int sum = 0;
        while (i > 0) {
            sum += arr[i], i -= LBS(i);
        }
        return sum;
    }
    
    void add(int i, int value) {
        while (i <= n) {
            arr[i] += value, i += LBS(i);
        }
        return ;
    }
    
    int main() {
        cin >> n >> m;
        int val, ans = 0;
        for (int i = 1; i <= n; i++) {
            cin >> val;
            ans = val - ans;
            add(i, ans);
            ans = val;
        }
        int x, y, z, s;
        while (m > 0) {
            cin >> x ; 
            if (x == 1) {
                cin >> y >> z >> s;
                add(y, s);
                add(z + 1, -s); // [y, z] 只改变arr[y], arr[z+1]
            }
            if (x == 2) {
                cin >> s;
                cout << sum(s) << endl;
            }
            m -= 1;    
        } 
        return 0;
    }
    
    

    相关文章

      网友评论

        本文标题:P3368【模板】树状数组2

        本文链接:https://www.haomeiwen.com/subject/nxbmiqtx.html