树状数组入门

树状数组比线段树要简单,可以用树状数组解决的问题都可以用线段树解决
把树状数组及时树状的数组,可以借助二叉树记忆、理解:
这里写图片描述
二叉树变形之后,如下图:
这里写图片描述
定义每一列的顶端结点C[]数组 ,如下图:
这里写图片描述

C[i]代表 子树的叶子结点的权值之和
如图可以知道
C[1]=A[1];
C[2]=A[1]+A[2];
C[3]=A[3];
C[4]=A[1]+A[2]+A[3]+A[4];
C[5]=A[5];
C[6]=A[5]+A[6];
C[7]=A[7];
C[8]=A[1]+A[2]+A[3]+A[4]+A[5]+A[6]+A[7]+A[8];

将C[i]数组的结点序号转化为二进制
1=(001) C[1]=A[1];
2=(010) C[2]=A[1]+A[2];
3=(011) C[3]=A[3];
4=(100) C[4]=A[1]+A[2]+A[3]+A[4];
5=(101) C[5]=A[5];
6=(110) C[6]=A[5]+A[6];
7=(111) C[7]=A[7];
8=(1000) C[8]=A[1]+A[2]+A[3]+A[4]+A[5]+A[6]+A[7]+A[8];
对照式子可以发现 C[i]=A[i-2^k+1]+A[i-2^k+2]+……A[i]; (k为i的二进制中从最低位到高位连续零的长度)
例如i=8时,k=3;
现在引入lowbit(x)

///lowbit()函数返回整数的二进制末尾零的个数
int lowbit(int i)
{
    return i&(-i);
}
///计算机总存储的为补码,首先计算出整数的原码,再由原码转化为反码,最后由反码得到补码,正整数的补码与原码相同,负数的补码则要经过一系列转化
///lowbit(6):(0110)&(1010)==(0010),所以lowbit(6)返回2;
///c[6]=A[6-2^1+1]+A[6-2^1+2]==A[5]+A[6];
///lowbit(5):(0101)&(1011)==(0001),所以lowbit(5)返回1;
///C[5]=A[5-2^0+1]==a[5];

下面说一下树状数组另一个重要的函数getsum()///区间求和

/// 求和i到1之间所有数求和
int getsum(int i)
{
    int ans=0;
    while (i>0)
    {
      ans+=c[i];
      i-=lowbit(i);
    }
    return ans;
}
///getsum()函数需要借助lowbit()函数
///getsum(7):sum=A[1]+A[2]+A[3]+A[4]+A[5]+A[6]+A[7];
///7>0;-->ans+=C[7];i=7-lowbit(7)==6;
///6>0;-->ans+=C[6];i=6-lowbit(6)==4;
///4>0;-->ans+=C[4];i=4-lowbit(4)==0;
///0==0;-->break;
///因为C[6]=A[5]+A[6];C[4]=A[4]+A[3]+A[2]+A[1];
///所以sum==C[7]+C[6]+C[4];
///因为C[6]=A[5]+A[6];C[4]=A[4]+A[3]+A[2]+A[1];
///所以sum==C[7]+C[6]+C[4];

现在介绍单点更新函数 updata()

///单点更新
void updata(int i,int value)///i更新的的起始位置,更新的终点为n;value为每个结点更新的值
{
    while(i<=n)
    {
        c[i]+=value;
        i+=lowbit(i);
    }
}
///updta(3,2)(n==8)
///3<=8;-->C[3]+=2;i+=lowbit(3);i==4;
///4<=8;-->C[4]+=2:i+=lowbit(4);i==8;
///8<=8;-->c{8]+=2;i+=lowbit(8);i==16;
///16>8-->break;
///因为C[8]=C[4]+C[6]+A[7]+A[8];  C[4]=A[1]+A[2]+A[3]+A[4];  C[3]=A[3];C[8],C[4], 中都包含A[3];
///所以A[3]更新之后C[3]、C[4]、C[8]也要更新

树状数组常用的的被调函数:

///lowbit()函数返回整数的二进制末尾零的个数
int lowbit(int i)
{
    return i&(-i);
}
/// 求和i到1之间所有数求和
int getsum(int i)
{
    int ans=0;
    while (i>0)
    {
      ans+=c[i];
      i-=lowbit(i);
    }
    return ans;
}
///单点更新
void updata(int i,int value)
{
    while(i<=n)
    {
        c[i]+=value;
        i+=lowbit(i);
    }
}

简单例题:HDU1166
HDU1556
POJ2299

猜你喜欢

转载自blog.csdn.net/qq_39535750/article/details/79348832