
http://www.java3z.com/cwbwebhome/article/article1/1369.html推荐的博文
referrence:http://community.topcoder.com/tc?module=Static&d1=tutorials&d2=binaryIndexedTrees
对于正整数,我们定义lowbit(x)为x的二进制表达式中最右边1所对应的值。对于节点i,如果它是左子节点,那么父节点的编号就是i+lowbit(i),如果它是右子节点,那么父节点的编号是i-lowbit(i),构造一个辅助数组C,其中 Ci=A[i-lowbit(i)+1]+...+A[i]。
前缀和S[i]:顺着节点i往左走,边走边“往上爬”,把沿途经过的C[i]累加起来
修改一个A[i],从C[i]开始往右走,边走边“往上爬”,沿途修改所有节点对应的C[i]
注意:树状数组的下标永远是从1开始的
树状数组求逆序对的原理:
前面有i-1个数,把每次输入的数看作树状数组的下标,设置增加的变量为1,算其前缀和(有多少个1就有多少个顺序对),然后减去顺序对就是答案,方案有两种(本质是一样的):
1、
ans+=(i-1-sum(a));
add(a);
2、
add(a);
ans+=(i-sum(a));
模板:
#define MARK 50005
int c[MARK],n;
int lowbit(int x)
{
return x&-x;
}
int sum(int x) //计算最大下标为s的前缀和
{
int ret=0;
while(x>0)
{
ret+=c[x];x-=lowbit(x);
}
return ret;
}
void add(int x,int d) //下标x的数增加d,对应的c数组也会有变化
{
while(x<=n)
{
c[x]+=d;x+=lowbit(x);
}
}
如果我们要计算某个下标x的值,我们可以sum(x)-sum(x-1),时间为O(2*log(N)),但是我们有更好的算法:
/*时间复杂度为:(c*logN),c小于1*/
int readSingle(int x){
int ret = c[x]; //我们知道c[x]是左子树元素之和(包含x为下标的元素)
if (x > 0){
int z = x - (x&-x); //我们知道c[x]=A[x-lowbit[x]+1]+...+A[i],z很明显是前一个元素
x--;
while (x != z){
ret -= c[x];
x -= (x & -x);
}
}
return ret;
}
附加个论文图(假设计算下标为12的数):

假设我们要求某个区间内和等于val的下标(规定元素都是非负的),


看到了吗?越左的tree[i]越大。所以我们可以用二分查找来求:
// if in tree exists more than one index with a same
// cumulative frequency, this procedure will return
// some of them (we do not know which one)
// bitMask - initialy, it is the greatest bit of MaxVal
// bitMask store interval which should be searched
int find(int cumFre){
int idx = 0; // this var is result of function
while ((bitMask != 0) && (idx < MaxVal)){ // nobody likes overflow :)
int tIdx = idx + bitMask; // we make midpoint of interval
if (cumFre == tree[tIdx]) // if it is equal, we just return idx
return tIdx;
else if (cumFre > tree[tIdx]){
// if tree frequency "can fit" into cumFre,
// then include it
idx = tIdx; // update index
cumFre -= tree[tIdx]; // set frequency for next loop
}
bitMask >>= 1; // half current interval
}
if (cumFre != 0) // maybe given cumulative frequency doesn't exist
return -1;
else
return idx;
}
// if in tree exists more than one index with a same
// cumulative frequency, this procedure will return
// the greatest one
int findG(int cumFre){
int idx = 0;
while ((bitMask != 0) && (idx < MaxVal)){
int tIdx = idx + bitMask;
if (cumFre >= tree[tIdx]){
// if current cumulative frequency is equal to cumFre, 考虑存在0元素
// we are still looking for higher index (if exists)
idx = tIdx;
cumFre -= tree[tIdx];
}
bitMask >>= 1;
}
if (cumFre != 0)
return -1;
else
return idx;
}
二维:

假设每个格子代表一个数A[i][j],i是横坐标,j是纵坐标,左上角的坐标为(1,1)我们要求红色区域元素之和,设sum(i,j)表示以i,j坐标为右下角坐标,以0,0为左上角坐标矩形内的元素之和,
sum(c,d):绿色+黄色+红色+蓝色
sum(c,b-1):绿色+蓝色
sum(a-1,d):绿色+黄色
sum(a-1,b-1):绿色
则红色区域元素之和=sum(c,d)-sum(c,b-1)-sum(a-1,d)+sum(a-1,b-1)
#define N 1005
int C[N][N]; //使用C之前,先清0
int sum(int x,int y) //x是横坐标,y是纵坐标
{
int ret=0,i,j;
for(i=x;i>0;i-=(i&-i))
for(j=y;j>0;j-=(j&-j))
ret+=C[i][j];
return ret;
}
void add(int x,int y,int d) //d是需要增加的值
{
int i,j;
for(i=x;i<N;i+=(i&-i))
for(j=y;j<N;j+=(j&-j))
C[i][j]+=d;
}
三维:
#define N 105
int c[N][N][N],n,m;
int sum(int x,int y,int z)
{
int ret=0,i,j,k;
for(i=x;i;i-=(i&-i))
for(j=y;j;j-=(j&-j))
for(k=z;k;k-=(k&-k))
ret+=c[i][j][k];
return ret;
}
void add(int x,int y,int z,int d)
{
int i,j,k;
for(i=x;i<=n;i+=(i&-i))
for(j=y;j<=n;j+=(j&-j))
for(k=z;k<=n;k+=(k&-k))
c[i][j][k]+=d;
}
/* add(x2+1,y2+1,z2+1,1);
add(x1,y2+1,z2+1,1);
add(x2+1,y1,z2+1,1);
add(x1,y1,z2+1,1);
add(x1,y2+1,z1,1);
add(x2+1,y1,z1,1);
add(x2+1,y2+1,z1,1);
add(x1,y1,z1,1);
*/
来源:https://www.cnblogs.com/A-way/archive/2013/05/20/3089637.html