您的位置:首页 > 其它

-----树状数组的理解

2017-04-06 21:25 204 查看
今晚学了树状数组…所以呢我来总结一下自己对它的理解…



这图是在网上随便找找的…

由图可以得出:

c1=a1;

c2=c2+c1=a1+a2;

c3=a3;

c4=c4+c3+c2=a1+a2+a3+a4;

c5=a5;

c6=c6+c5=a5+a6;

c7=a7;

c8=c8+c7+c6+c4=a1+a2+a3+a4+a5+a6+a7+a8;

前k项和:

s1=c1=a1;

s2=c2+c1=a1+a2;

s3=c3=a3;

s4=c4+c3+c2=a1+a2+a3+a4;

s5=a5;

s6=c6=c6+c5=a5+a6;

s7=c7=a7;

s8=c8+c7+c6+c4=a1+a2+a3+a4+a5+a6+a7+a8;

然后要引入一个lowbit 函数:

int lowbit( int x )

{

return x&(-x);

}

这个函数返回的是2^k, 其中k是x的二进制中末尾的0的个数;

解释一下 x&( -x )的意义:如x 是8,则用二进制表示 x=1000,

-x=1000, 末尾有3个0,所以k=3, lowbit 函数返回的是2^3=8;



你还发现c[ i ]里面包含着 x=lowbit( i )个a[i]的和

在这里说一下父节点,方便待会树状数组的建立:

比如:

c1的父节点有:c2,c4,c8;

c2的父节点有:c4,c8;

c3的父节点有:c4,c8;

….

然后你会有一个神奇的发现:c[ i ]的父节点为c[ i+lowbit( i ) ]

当我们进行树状数组的建立时,就会用到这个发现:

void update( int i , int x )/// i 代表要更改的点,x代表变化量

{

while( i<=n )

{

c[i]+=x;

i+=lowbit( i );///代表每一个父节点

}

}

for(int i=1; i<=n; i++)///树状数组的建立

{

int data;

scanf(“%d”,&data);///data就是数组a的元素

update(i,x);///每输入一个元素,就对它的所有父节点进行更新;并且你会发现,节点只保存了,当前已经输入了的值;

}

当我们求前k项和的时候,你会发现一个神奇的规律:

int _sum(int k)

{

while(k>0)

{

sum+=c[k];

k=k-lowbit(k);

}

return sum;

}

比如k=5,即求前5项和:s5=a5

k=5;

k=k-lowbit( 5)=5-5=0;

比如k=4,即求前4项和:s4=c4+c3+c2

k=4;

k=k-lowbit( 4)=4-1=3;

k=k-lowbit( 3)=3-1=2;

k=k-lowbit( 2)=2-2=0;

所以s4=c4+c3+c2;

树状数组单点更改:



我们要知道,当某个点的值改变的时候,它的父节点也会发生改变,比如更改c1 ,它的父节点c2,c4,c8也会发生能够改变:

void update( int i , int x )/// i 代表要更改的点,x代表变化量

{

while( i<=n )

{

c[i]+=x;

i+=lowbit( i );///代表每一个父节点

}

}

比如更改c1, i=1;

i=i+lowbit( 1 )=1+1=2;

i=i+lowbit( 2 )=2+2=4;

i=i+lowbit( 4 )=4+4=8;

反正这些规律好神奇…
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: