zoukankan      html  css  js  c++  java
  • 树状数组

    相比于线段树,节省了很多的内存
    特殊用处:求逆序对以及在CDQ分治里嵌套用

    一维树状数组

    img

    黑色部分代表原来的数组,用(A[i])表示,红色部分代表树状数组,用(C[i])表示。

    (C[1] = A[1]\C[2] = A[1] + A[2]\C[3]=A[3]\C[4]=A[1]+A[2]+A[3]+A[4]\C[5]=A[5]\C[6] = A[5]+A[6]\C[7] = A[7]\C[8]=A[1]+A[2]+A[3]+A[4]+A[5]+A[6]+A[7]+A[8])

    发现有规律,(C[i] = A[i - 2^k + 1] + A[i - 2^k+2]+...A[i])k为二进制中最低位到最高位连续0的长度

    那么对于求和,求前7项和,(sum = C[7]+C[6]+C[4])

    可以得到(SUM[i] = C[i] + C[i - 2^{k_1}]+C[(i-2^{k_1}) -2^{k_2}]+...)

    lowbit

    定义(lowbit(x))是x的二进制表示形式中最低位的1和后面的0组成的数

    二进制的负数是正数取反加1。如果x = 12(1100),那么-x = -12(0100)。lowbit(x)=4

    int lowbit(int x){
        return x & (-x);
    }
    

    更新

    对于单点修改,如果要修改(A[3])的值,那么对于(C[3],C[4],C[8])都要进行修改

    是一个向右上跳的过程

    img

    void update(int i, int k){
        for(; i <= n; i += lowbit(i))c[i] += k;
    }
    

    查询

    ([1,i])的和。比如查询[1,5]的和,就是(C[4]+C[5])

    是一个向左上角跳的过程

    int query(int i){
        int ans = 0;
        for(; i > 0; i -= lowbit(i))ans += c[i];
        return ans;
    }
    

    因为求出来的是前缀和形式,所以对于求[L,R],可以用query(R) - query(L-1);

    模板

    单点修改 + 区间查询

    传送门

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    using namespace std;
    const int N = 1e5 + 5;
    struct BIT{
        int c[N];
        BIT(){memset(c, 0, sizeof(c));}
        int lowbit(int x){
            return x & (-x);
        }
        void update(int x, int k){// 修改a[x] 的值
            for(; x <= N; x += lowbit(x))
                c[x] += k;
        }
        int query(int x){//查询[1, x]的值
            int ans = 0;
            for(; x > 0; x -= lowbit(x)) 
                ans += c[x];
            return ans;
        }
    };
    int main(){
        BIT b;
        return 0;
    }
    

    区间修改,单点查询

    传送门

    利用前缀和和差分思想,初始的树状数组是一个差分数组 对于每一个区间[l,r]修改,变为b[l]++, b[r + 1]-- 对于单点查询,就是[1,x]的前缀和

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #define ll long long
    using namespace std;
    const int N = 5e5 + 5;
    int n, m;
    struct BIT{
        ll c[N];
        BIT(){memset(c, 0, sizeof(c));}
        ll lowbit(ll x){
            return x & (-x);
        }
        void Add(int x, ll k){
            for(; x <= N; x += lowbit(x))c[x] += k;
        }
        ll Ask(ll x){//[1, x]和
            ll ans = 0;
            for(;x; x -= lowbit(x))ans += c[x];
            return ans;
        }
    };
    int main(){
        BIT bit;
        ll last = 0, now;
        scanf("%d%d", &n, &m);
        for(int i = 1; i <= n; i++){
            scanf("%lld", &now);
            bit.Add(i, now - last);//差分
            last = now;
        }
        for(int i = 1; i <= m; i++){
            ll op, l, r, c;
            scanf("%lld", &op);
            if(op == 1){
                scanf("%lld%lld%lld", &l, &r, &c);
                bit.Add(l, c); bit.Add(r + 1, -c);//差分
            }else {
                scanf("%lld", &l);
                printf("%lld
    ", bit.Ask(l));
            }
        }
        return 0;
    }
    

    二维树状数组

    struct BIT{
        int c[N][N];
        BIT(){memset(c, 0, sizeof(c));}
        int lowbit(int x){
            return x & (-x);
        }
        void add(int x, int y, int k){//点a[x][y] + k
            while(x <= N){
                while(y <= N){
                    c[x][y] += k;
                    y += lowbit(y);
                    x += lowbit(x);
                }
            }
        }
        int sum(int x, int y){//求[1][1] 到[x][y] 的和
            int ans = 0;
            while(x){
                while(y){
                    ans += c[x][y];
                    x -= lowbit(x);
                    y -= lowbit(y);
                }
            }
            return ans;
        }      
    };
    
  • 相关阅读:
    学生管理系统(2:添加主界面窗口)
    Qfile
    QButtonGroup
    comboBox
    QLineEdit
    QMessageBox
    实现简单的计算器(控制器代码)
    实现简单的计算器(计算功能模块实现)
    网络编程基础【HTML编程】
    网络编程基础【正则表达式】
  • 原文地址:https://www.cnblogs.com/Emcikem/p/11545016.html
Copyright © 2011-2022 走看看