树状数组总结

如图可以知道
将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] } }

 

 
posted @ 2021-01-26 19:53  夜灯长明  阅读(65)  评论(0编辑  收藏  举报