【数据结构】树状数组

【树状数组】

   顾名思义:本质是数组,逻辑上是被构造出来的二叉树,方便求前缀和,以及更新元素值

  关键:设原数组为A,设构造出来的树状数组为 C,令 

  C i  = A i-lowbit(i) + 1 + A i-lowbit(i) + 2  + .......... + Ai , 其中lowbit(i) = i & (-i)

  所以

  操作1:求前缀和 Si = Ci + Ci-lowbit(i) + ......    直到 C 的下标  index = i - lowbit(i) = 1

  操作2:元素A[x] 的值加上 y ,需要更新包含A[x] 的区间:

                       C[x] = C[x] + y

                       x = x + lowbit(x)    C[x]  =  C[ x ]  + y

                        ........

                       直到 x > n (n 为元素个数) 

  可以得以上两个操作的时间复杂度均为 O( logn )

【应用】

  求逆序对

【优化】

   

【模板】

/*
树状数组模板
注意数组C[]下标是从1开始
by chsobin
*/
const
int maxn = 32005; int c[maxn]; void init(){ memset(c, 0, sizeof(c)); } int lowbit(int x){ return x & (-x); } void update(int x, int add){ while(x<=maxn){ c[x] += add; x += lowbit(x); } } int getsum(int x){ int s = 0; while(x > 0){ s += c[x]; x -= lowbit(x); } return s; }

 

【题目】

 hdu1541

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn = 32005;
int c[maxn];
int ans[maxn];
void init(){
        memset(c, 0, sizeof(c));
        memset(ans, 0, sizeof(ans));    
}
int lowbit(int x){
    return x & (-x);
}
void update(int x, int add){
    while(x<=maxn){
        c[x] += add;
        x += lowbit(x);
    }
}
int getsum(int x){
    int s = 0;
    while(x > 0){
        s += c[x];
        x -= lowbit(x);
    }
    return s;
}


int main(){
    int n, x, y;
    while(~scanf("%d", &n)){
        init();
        for(int i=0;i<n;++i){
            scanf("%d%d", &x, &y);
            x++;                     //很重要,被这个坑了,一直超时 
            ans[getsum(x)]++;
            update(x, 1);
        }
        for(int i=0;i<n;++i) printf("%d\n", ans[i]);        
    }
    return 0; 
} 
AC Code

 hdu4970

 树状数组区间更新

参考自http://blog.csdn.net/idealism_xxm/article/details/51051342

【参考】

posted @ 2018-01-23 02:27  chsobin  阅读(138)  评论(0编辑  收藏  举报