1、树状数组最早用于数据压缩。
2、c[i]的初始位置是去掉最低位的1之后加上1.(最后一个1代表的权值表示c中拥有a的个数。)
3、c[i]下标的起点是下标 x=i-[i&(-i)]+1;
4、树状数组之所以高效简洁的原因就是能够利用位运算直接求出i对应的lowbit。
5、某一a[i]的值,位于数状数组中位置关系是i=i+lowbit(i)
6、树状数组与原始数组的关系:
c[i]=a[i-lowbit(i)+1]+...a[i];
以及
a[i]∈c[i],c[i=i+lowbit(i)],c[i=i+lowbit(i)]...
7、树状数组与累加数组:
sum[i]=c[i]+c[i=i-lowbit(i)]+c[i=i-lowbit(i)]+...;(最后一个1代表的权值与i位置的差即为sum包含的数的个数0的时候是1)
8、扩展到多维时的情形:
/*query求和查询*/
9、树状素组特点:
(1)树状数组十分容易进行编程实现。
(2)树状数组的每个操作花费常数时间或是o(log2N)的时间。
(3)树状数组需要线性的存储空间o(n),只维护c数组。
(4)树状数组可以扩展为n维的情况。
10、总结:
弊端:
(1)树状数组的致命缺点是无法记录一些附加信息,比如:不相交区间的个数,就无法用树状数组维护
(2)树状数组的应用范围是很窄的。(求和的问题可以用树状数组,如果求最大值操作,而且没有删除操作的话,那么也能够用树状数组。)
2、c[i]的初始位置是去掉最低位的1之后加上1.(最后一个1代表的权值表示c中拥有a的个数。)
3、c[i]下标的起点是下标 x=i-[i&(-i)]+1;
4、树状数组之所以高效简洁的原因就是能够利用位运算直接求出i对应的lowbit。
# define lowbit(x)((x)&(-x));
int lowbit(int i){
return i&(-i);
}
5、某一a[i]的值,位于数状数组中位置关系是i=i+lowbit(i)
void update(int i,int data){
while(i<=n){
c[i]+=data; //改变需要修改的数据。
i+=lowbit(i); //a[i]所在的下一个c中的位置。
}
}
6、树状数组与原始数组的关系:
c[i]=a[i-lowbit(i)+1]+...a[i];
以及
a[i]∈c[i],c[i=i+lowbit(i)],c[i=i+lowbit(i)]...
7、树状数组与累加数组:
sum[i]=c[i]+c[i=i-lowbit(i)]+c[i=i-lowbit(i)]+...;(最后一个1代表的权值与i位置的差即为sum包含的数的个数0的时候是1)
int query(int i)
{
int ans=0;
while(i>0){
ans+=c[i];
i-=lowbit(i);
}
return ans;
}
8、扩展到多维时的情形:
void update(int x,int y,int data){
for(;x<=n;x+=lowbit(x))
for(j=y;j<=m;j+=lowbit(j))
c[x][j]+=data;
}/*updata数据插入*/
int query(int x,int y)
{
int ans=0;
for(;x>0;x-=lowbit(x))
for(j=y;j>0;j-=lowbit(j))
ans+=c[x][j];
return ans;
}
/*query求和查询*/
9、树状素组特点:
(1)树状数组十分容易进行编程实现。
(2)树状数组的每个操作花费常数时间或是o(log2N)的时间。
(3)树状数组需要线性的存储空间o(n),只维护c数组。
(4)树状数组可以扩展为n维的情况。
10、总结:
弊端:
(1)树状数组的致命缺点是无法记录一些附加信息,比如:不相交区间的个数,就无法用树状数组维护
(2)树状数组的应用范围是很窄的。(求和的问题可以用树状数组,如果求最大值操作,而且没有删除操作的话,那么也能够用树状数组。)