树状数组(Fenwick_tree),最早由Peter M. Fenwick于1994年以A New Data Structure for Cumulative Frequency Tables为题发表在SOFTWARE PRACTICE AND EXPERIENCE。其初衷是解决数据压缩里的累积频率(Cumulative Frequency)的计算问题,现多用于高效计算数列的前缀和。它可以以O(\log n)的时间得到\sum_{i=1}^N a[i],并同样以O(\log n)对某项加一个常数。

基本操作:

  1)新建;

  2)修改;

  3)求和;

 

lowbit求法:

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

 

新建:

定义一个数组 BIT,用以维护A的前缀和,则:

BIT_i=\sum_{i=i-lowbit(i)+1}^{i}A_i

具体能用以下方式实现:

void build()
{
    for (int i=1;i<=MAX_N;i++)
    {
        BIT[i]=A[i];
        for (int j=i-1; j>i-lowbit(i); j--)
            BIT[i]+=A[j];
    }
}

修改:

假设现在要将A[i]的值增加delta,

那么,需要将BIT[i]覆盖的区间包含A[i]的值都加上K.

这个过程可以写成递归,或者普通的循环.

需要计算的次数与数据规模N的二进制位数有关,即这部分的时间复杂度是O(LogN)

void edit(int i, int delta)
{
    for (int j = i; j <= MAX_N; j += lowbit(j))
        BIT[j] += delta;
}

求和:

假设我们需要计算\sum_{i=1}^{k}A_i的值.

  1. 首先,将ans初始化为0,将i计为k.
  2. 将ans的值加上BIT[P]
  3. 将i的值减去lowbit(i)
  4. 重复步骤2~3,直到i的值变为0
int sum (int k)
{
    int ans = 0;
    for (int i = k; i > 0; i -= lowbit(i))
        ans += BIT[i];
    return ans;
}

 

posted on 2016-04-10 18:46  yoyo_sincerely  阅读(239)  评论(0编辑  收藏  举报