树状数组总结
如图可以知道 将C[]数组的结点序号转化为二进制 个数 lowbit(x) == 2^k 1=(001) C[1]=A[1]; 1 1 k=0 2=(010) C[2]=A[1]+A[2]; 2 2 k=1 3=(011) C[3]=A[3]; 1 1 k=1 4=(100) C[4]=A[1]+A[2]+A[3]+A[4]; 4 4 k=2 5=(101) C[5]=A[5]; 1 1 k=0 6=(110) C[6]=A[5]+A[6]; 2 2 k=1 7=(111) C[7]=A[7]; 1 1 k=0 8=(1000) C[8]=A[1]+A[2]+A[3]+A[4]+A[5]+A[6]+A[7]+A[8]; 8 8 k=3
C[i]=A[i-2^k+1]+A[i-2^k+2]+......A[i]; (k为i的二进制中从最低位到高位连续零的长度)
现在引入lowbit(x)
lowbit(x) 其实就是取出x的最低位1 换言之 lowbit(x)=2^k 其实lowbit(x)也就是C[x]是2^k 个A数组之和
lowbit(x)函数
int lowbit(int x) { return x&(-x); }
单点更新函数
void add(int x,int y) { while (x <= n) { c[x]+=y; x += lowbit(x); } }
求前x项和函数
int get_sum(int x) { int sum = 0; while (x > 0) { sum += c[x]; x -= lowbit(x); } return sum; }
树状数组求逆序对
假设给定的序列为 4 3 2 1,我们从左往右依次将给定的序列输入,每次输入一个数temp时,就将当前序列中大于temp的元素的个数计算出来,并累加到ans中,最后ans就是这个序列的逆序数个数。
序列的变化(下划线为新增加元素) |
序列中大于新增加的数字的个数 |
操作 |
{ } |
0 |
初始化时序列中一个数都没有 |
{4 } |
0 |
往序列中增加4,统计此时序列中大于4的元素个数 |
{4 3 } |
1 |
往序列中增加3,统计此时序列中大于3的元素个数 |
{4 3 2} |
2 |
往序列中增加2,统计此时序列中大于2的元素个数 |
{4 3 2 1} |
3 |
往序列中增加1,统计此时序列中大于1的元素个数 |
当所有的元素都插入到序列后,即可得到序列{4 3 2 1}的逆序数的个数为1+2+3=6.
具体代码如下:
int get_sum(int x) //求出序列中比x小的数量
{ int sum = 0; while (x > 0)
{ sum += c[x]; x -= lowbit(x); } return sum; } void add(int x)//在序列中插入x
{ while (x <= n)
{ c[x]++; x += lowbit(x); } } int main() { for (int i = 1; i <= n; i++)
{ L[i] = i-get_sum(a[i] - 1)-1;//第i个插入,里面已经存在i-1个数,其中比a[i]小的数有get_sum(a[i]-1),a[i]的逆序对为i-get_sum(a[i]-1)-1; add(a[i]);//插入a[i] } }