树状数组入门

关于lowbit运算

lowbit是找到数字x的二进制的最后一个一代表的数字, 例如lowbit(4)=lowbit((2)100)=100=4;
lowbit(6)=lowbit((2)110)=10=2;
lowbit(7)=lowbit((2)111)=1=1;
给定一个整数x,下面这段代码可以计算出区间[1,x]分成的O(log x)个小区间。

 while(x>0){
 	printf("[%d,%d]\n",x-(x&-x)+1,x);
 	x-=x&-x;
 }

树状数组

树状数组遍是一种数据结构,其基本用途是维护序列的前缀和。对于给定的序列a,我们建立一个数组c,其中c[x]保存序列a的区间[x-lowbit(x)+1,x]中所有数据的和,(可以说是序列的后lowbit(x)个数的和).
事实上,数组c可以看作一个如下图所示的树形结构,满足性质如下:
1.c[x]储存的是以他为根的所有叶节点的和。
2.所有内部节点c[x]的自建点个数等于lowbit(x)的位数
3.除树根外,每个内部节点c[x]的父节点是c[x+lowbit(x)]/
4.树的深度等于O(logN)。
如果N不是二的整次幂,那么树状数组就是一个具有相同性质的森林。
在这里插入图片描述

树状数组的操作

树状数组的操作主要有两个,第一个是查询前缀和,即序列a第1-x的数的和,
如下

int ask(int x){
	int ans=0;
	for(:x;x-=x&-a){
		ans+= c[x];
	}
	return ans;
}

第二个操作是单点增加,即给第x个数加上y,只有节点c[x],和c[x]的祖先需要改动,至多有O(log (N))个,所以可以在log(N)的时间里操作完成。


void add(int x,int y){
	for(;x<=N;x+=x&-x)c[x]+=y;
}

在执行所有操作之前,我们需要对树状数组进行初始化操作,针对原始序列a构造树状数组。
为了简便,开始的方法是:建立一个全为零的数组c,然后进行add,完成对序列的添加,时间复杂度为O(NlogN).
更高效的算法是:自小到大考虑剋个节点x,借助lowbit运算扫描子节点并求和。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值