基本概念
设A[1..N]为一个长为N的序列,即对于序列A有以下操作:
【1】修改操作:将A[x]的值加上c;
【2】求和操作:求此时A[l..r]的和。
} 原数组a
} 树状数组C
C1=a1
C2=a1+a2
C3=a3
C4=a1+a2+a3+a4
C5=a5
C6=a5+a6
C7=a7
C8=a1+a2+a3+a4+a5+a6+a7+a8
……
C[X]的含义
C[x]管辖的区间为2^k个元素,其中k为x二进制末尾0的个数
C[x] = a[x– 2^k + 1] + … + a[x]
K的计算
求k的函数代码如下:
int Lowbit(int t)
{
return t & ( -t );
}
快速求和(复杂度logN)
Sum[9] = C[9]+C[8]
Sum[8] = C[8]
Sum[7] = C[7]+C[6]+C[4]
…..
求a[1]—a[end]和的函数代码如下:
int Sum(int end)
{
int sum = 0;
while(end > 0)
{
sum += C[end];
end -= Lowbit(end);
}
return sum;
}
修改数组a的某个元素值(复杂度logN)
例如 a[3]+x
影响C[3], C[4], C[8]…
void Update(int pos , int num)
{
while(pos <= n)
{
C[pos] += num;
pos += Lowbit(pos);
}
}
线段树与树状数组比较
} 树状数组和线段树一样,是一种很高效的数据结构。但是在于空间耗费较小。
} 对于长度为n的线段(区间),线段树需要2n的空间,而树状数组只要n即可。
} 树状数组的另一个优点是编程简单。
} 树状数组的致命缺点是无法记录一些附加信息。
} 比如“区间总长度” 就无法用树状数组维护。
} 树状数组的应用范围是很窄的
} 求和的问题可以用树状数组;
} 如果求最大值操作、而且没有删除操作的话,那也能够用树状数组