树状数组是一种非常巧妙的数据结构。对于一个普通数组,可以构造出一个对应的树状数组。普通数组中的元素存放的只是本身的信息,但树状数组中的元素存放的却是多个原数组的信息。
对于一个非负整数x,我们可以将它表示为二进制,设它的二进制形式中,结尾的0的个数为k。
对于树状数组,它的x位置上的元素表示的是原数组从x位置开始,往后数2^k个元素的信息(一般是它们的和,也可以是最大值或最小值)。
比如:
x=1时2^k=1,即它只包含本身的信息。其他奇数也一样。
x=2时2^k=2,即它包含2和1位置上的元素信息
x=4时2^k=4,即它包含4、3、2、1位置上的元素信息
x=6时2^k=2,即它包含6和5位置上的元素信息
……
对于x计算出它对应的2^k的方法非常简单,只要通过下面的函数:
int lowbit(int x)
{
return x & (-x);
}
这是一个非常巧妙的函数,对于树状数组的某个位置x而言,x + lowbit(x)表示它的上一级的结点,即包含它的信息的结点,而x - lowbit(x)表示比它小的不被它包含的最大结点。
比如当x=2时,lowbit(x)=2,则x+lowbit(x)=4,表示它的上一级结点是4,因为4包含了4、3、2、1的信息。
当x=7时,lowbit(x)=1,则x-lowbit(x)=6,表示比它小的不被它包含的最大结点是6。
树状数组的主要操作:
1、在某个位置的结点处增加一个值:在改变了原数组中元素的值之后,需要逐步向上修改上一级结点的信息。
2、统计第一个元素到当前元素的和:设置一个表示和的树状数组,然后使用上面的lowbit函数不断查找下一个不被包含的点,把所有的和加起来即可。
3、统计区间和:使用操作2中的方法,用较大的区间减去较小的区间就得到所求区间和了。
//BinaryIndexedTree.h
#ifndef _BINARY_INDEXED_TREE_
#define _BINARY_INDEXED_TREE_
#include <iostream>
#include <vector>
using namespace std;
class BinaryIndexedTree
{
public:
BinaryIndexedTree(int _size);
~BinaryIndexedTree();
void addValue(int _pos, int _val); //向数组的某个位置的元素增加某个值
int getSum(int _beg, int _end); //计算某个区间的元素的和
int lowbit(int _val); //计算某个数的二进制表示中,末尾有多少个0
protected:
private:
int size; //数组大小
vector<int> number; //原始数组
vector<int> sum; //树状数组
};
#endif
//BinaryIndexedTree.cpp
#include "BinaryIndexedTree.h"
using namespace std;
BinaryIndexedTree::BinaryIndexedTree(int _size): size(_size)
{
number.resize(_size + 1);
sum.resize(_size + 1);
for (int i = 1; i <= size; ++i)
{
sum[i] = 0;
}
int num = 0;
cout << "input elements:" << endl;
for (int i = 1; i <= size; ++i)
{
cout << i << ": ";
cin >> num;
addValue(i, num);
}
}
BinaryIndexedTree::~BinaryIndexedTree()
{
number.clear();
sum.clear();
}
int BinaryIndexedTree::lowbit(int _pos)
{
return _pos & (-_pos);
}
void BinaryIndexedTree::addValue(int _pos, int _val)
{
while (_pos <= size)
{
sum[_pos] += _val;
_pos += lowbit(_pos);
}
}
int BinaryIndexedTree::getSum(int _beg, int _end)
{
if (_beg > _end)
{
int t = _beg;
_beg = _end;
_end = t;
}
if (_beg <= 0 || _end > size) return INT_MIN;
int sumbeg = 0;
int sumend = 0;
_beg -= 1;
while (_beg > 0)
{
sumbeg += sum[_beg];
_beg -= lowbit(_beg);
}
while (_end > 0)
{
sumend += sum[_end];
_end -= lowbit(_end);
}
return sumend - sumbeg;
}
//main.cpp
#include "BinaryIndexedTree.h"
#include <string>
using namespace std;
int main()
{
int beg, end;
int val, pos;
int size;
string str;
cout << "input the size: ";
cin >> size;
BinaryIndexedTree tree(size);
while (cin >> str)
{
if (str == "INSERT" || str == "insert")
{
cin >> pos >> val;
tree.addValue(pos, val);
}
else if (str == "SUM" || str == "sum")
{
cin >> beg >> end;
cout << tree.getSum(beg, end) << endl;
}
else break;
}
return 0;
}