树状数组

前言

话说以前学竞赛真没学好啊……好多算法都学得模模糊糊的。这篇博客主要是复习。
直接开始吧。

树状数组

树状数组,即用数组达到树形结构的作用。

树状数组时间复杂度和线段树类似,但是常数会小很多,而且写起来更快。缺点是一些复杂的区间问题不能用树状数组。

讲解

在这里插入图片描述
上面是一棵二叉树。也是传统线段树的结构。

树状数组的结构和其类似,但是省去了一些节点以达到用数组建树。如下示例:
在这里插入图片描述

若称拓展数组为 C C C,原数组为 A A A,可发现:
C [ i ] = A [ i − 2 k + 1 ] + A [ i − 2 k + 2 ] + . . . + A [ i ] C[i]=A[i-2^k+1]+A[i-2^k+2]+...+A[i] C[i]=A[i2k+1]+A[i2k+2]+...+A[i]
其中 k k k i i i 的二进制中最低位到高位连续 0 0 0的长度。

根据上面的式子易得:
S u m [ i ] = C [ i ] + C [ i − 2 k 1 ] + C [ ( i − 2 k 1 ) − 2 k 2 ] + . . . Sum[i]=C[i]+C[i-2^{k1}]+C[(i-2^{k1})-2^{k2}]+... Sum[i]=C[i]+C[i2k1]+C[(i2k1)2k2]+...

问题是 2 k 2^k 2k 如何求,易得到 2 k = i 2^k = i 2k=i & ( i (i (i ^ ( i − 1 ) ) (i - 1)) (i1))。然而结论为 2 k = i 2^k=i 2k=i & ( − i ) (-i) (i)。具体的证明是用分类讨论,这里不多介绍。

在树状数组中,称这个 2 k 2^k 2klowbit

实现

具体不多讲了,看代码即可。

#define MAXN 100005
#define lowbit(x) x & (-x) 
int C[MAXN], A[MAXN];
inline void Update(LL x,LL Val) // x位置增加 Val,注意到树状数组中x位的修改只会对x位后面的位置产生影响 
{
	while (x <= n)
	{
		C[x] += Val;
		x += lowbit( x );
	}
}
inline LL Query(LL x) // 1-x的前缀和
{
	LL Res = 0; 
	while (x > 0)
	{
		Res += C[x];
		x -= lowbit( x );
	}
	return Res;
}

拓展

区间更新,单点查询

方法为摒弃原数组,使用差分值建树。

规定 A [ 0 ] = 0 A[0] = 0 A[0]=0 A [ i ] = ∑ j = 1 i D [ j ] A[i] = \sum_{j=1}^{i} D[j] A[i]=j=1iD[j]

其中, D [ j ] = A [ j ] − A [ j − 1 ] D[j] = A[j] - A[j-1] D[j]=A[j]A[j1]

发现当 [ x , y ] [x,y] [x,y]的值改变,只有 D [ x ] D[x] D[x] D [ y + 1 ] D[y+1] D[y+1]的值发生改变。于是利用这个性质对 D D D数组建立树状数组。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值