zoukankan      html  css  js  c++  java
  • [转]树状数组的一些应用

    树状数组(BIT,Binary Indexed Tree) 

    先上一张经典的图吧。(也是盗的,地址见水印

    树状数组

    以下转自:http://blog.csdn.net/lawrence_jang/article/details/8054173

    1.单点增减+区间求和

    思路:C[x]表示该点的元素:sum(x)=C[1]+C[2]+……C[x]

    int arr[MAXN];  
    inline int sum(int x){int res=0;while(x)res+=arr[x],x-=lowbit(x);return res;}  
    inline void add(int x,int n){while(x<MAXN)arr[x]+=n,x+=lowbit(x);}  
    inline int query(int x,int y){return sum(y)-sum(x-1);} 

    2.区间增减+单点查询

    思路:C[x]表示该点元素与左边元素的差值:num[x]=C[1]+C[2]+……C[x]

    int arr[MAXN]  
    inline int sum(int x){int res=0;while(x)res+=arr[x],x-=lowbit(x);return res;}  
    inline void add(int x,int n){while(x<MAXN)arr[x]+=n,x+=lowbit(x);}  
    inline int update(int x,int y,int n){add(x,n);add(y+1,-n);}  

    3.区间增减+区间查询

    思路:C[x]表示该点元素与左边的差值

             sum(sum(C[j],j<=i)i<=x)  =  x*C[1]+(x-1)*C[2]+……+C[x]  =  (x+1)*sum(C[i],i<=x)-sum(i*C[i],i<=x); 

             则可以想到用C1[x]维护C[x]的值,C2[x]维护x*C[X]的值

    struct tree_array{  
        struct tree_array_single{  
            int arr[MAXN];
            void add(int x, int v) { while(x <= N) arr[x] += v, x += lowbit(x); }  
            int sum(int x) { int sum = 0; while(x) sum+=arr[x], x-=lowbit(x); return sum; }  
        } T1, T2;  
        void reset() { memset(T1.arr, 0, sizeof T1.arr); memset(T2.arr, 0, sizeof T2.arr); }
        void add(int x, int v) { T1.add(x, v); T2.add(x, x*v); }
        void update(int L, int R, int v) { add(L, v); add(R+1, -v); }   // [L,R]每个点值都增加v
        int sum(int x) { return (x+1)*T1.sum(x)-T2.sum(x); }            // 前x个数的和
        int query(int L,int R) { return sum(R)-sum(L-1); }              // 区间[L,R]的和
    };

    4.二维:单点增减(add) + 矩形求和(query)+ 矩形增减(update)+ 单点求值(sum)

    int arr[MAXN][MAXN]  
    inline void add(int x,int y,int v) {  
        for(int i=x;i<MAXN;i+=lowbit(i))
            for(int j=y;j<MAXN;j+=lowbit(j))
                arr[i][j]+=v;
    }  
    inline int sum(int x,int y){
        int res=0;
        for(int i=x;i;i-=lowbit(i))
            for(int j=y;j;j-=lowbit(j))
                res+=arr[i][j];
        return res;
    }
    inline int query(int L,int B,int R,int T) {
        return sum(R,T)+sum(L-1,B-1)-sum(R,B-1)-sum(L-1,T);
    }
    inline void update(int L,int B,int R,int T,int v){  // 左 下 右 上 要增加的值
        add(L,B,v); add(L,T+1,v); add(R+1,B,v); add(R+1,T+1,v);
    } 

    5.单点增减(add) + 立方体求和(query)+ 立方体增减(update) + 单点求值(sum)

    int arr[MAXN][MAXN][MAXN];  
    inline int sum(int x,int y,int z){  
        int res=0;  
        for(int i=x;i;i-=lowbit(i))  
            for(int j=y;j;j-=lowbit(j))  
                for(int k=z;k;k-=lowbit(k))  
                    res^=arr[i][j][k];  
        return res;  
    }  
    inline void add(int x,int y,int z,int v){   
        for(int i=x;i<MAXN;i+=lowbit(i))  
            for(int j=y;j<MAXN;j+=lowbit(j))  
                for(int k=z;k<MAXN;k+=lowbit(k))  
                    arr[i][j][k]+=v;  
    }  
    inline void update(int x1,int y1,int z1,int x2,int y2,int z2,int v){  
        add(x1,y1,z1,v);  
        add(x2+1,y1,z1,-v);add(x1,y2+1,z1,-v);add(x1,y1,z2+1,-v);  
        add(x2+1,y2+1,z1,v);add(x2+1,y1,z2+1,v);add(x1,y2+1,z2+1,v);  
        add(x2+1,y2+1,z2+1,-v);
    }  
    inline int query(int x1,int y1,int z1,int x2,int y2,int z2){  
        return sum(x2,y2,z2)  
        -sum(x2,y2,z1-1)-sum(x2,y1-1,z2)-sum(x1-1,y2,z2)  
        +sum(x2,y1-1,z1-1)+sum(x1-1,y2,z1-1)+sum(x1-1,y1-1,z2)  
        -sum(x1-1,y1-1,z1-1);  
    }

    6.RMQ

    inline void init()  
    {  
        memset(arr, 0, sizeof arr); 
        for(int i=1;i<=N;++i)  
            for(int j=i;j<=N&&arr[j]<num[i];j+=lowbit(j))  
                arr[j]=num[i];  
    }  
    inline int query(int L,int R)  
    {  
        int res=0;  
        for(--L;L<R;){  
            if(R-lowbit(R)>=L){res=max(res,arr[R]);R-=lowbit(R);}  
            else{res=max(res,num[R]);--R;}  
        }  
        return res;  
    }  
    inline void update(int x,int val)  
    {  
        int ori=num[x];  
        num[x]=val;  
        if(val>=ori)  
            for(int i=x;i<=N&&arr[i]<val;i+=lowbit(i))  
                arr[i]=val;  
        else{  
            for(int i=x;i<=N&&arr[i]==ori;i+=lowbit(i))  
            {  
                arr[i]=val;  
                for(int j=lowbit(i)>>1;j;j>>=1)  
                    arr[i]=max(arr[i],arr[i-j]);  
            }  
        }  
    }
  • 相关阅读:
    4种定位的区别
    tab切换插件
    CPU的cache知识
    linux free命令详解
    关于登录linux时,/etc/profile、~/.bash_profile等几个文件的执行过程
    职业规范(运维)
    数据库的横表和纵表
    Linux下的xargs的用法
    LINUX ulimit命令
    防火墙并发连接数
  • 原文地址:https://www.cnblogs.com/wenruo/p/5787418.html
Copyright © 2011-2022 走看看