数据结构-树状数组

树状数组是一种数据结构,能高效地解决区间查询和单点修改的问题。它基于位运算,利用lowbit()进行跳跃维护,具有O(n)的空间复杂度和O(nlogn)的时间复杂度。通过树状数组,可以实现单点修改和区间查询操作,相较于线段树,虽然功能稍弱,但代码简洁,易于理解。在后续的树套树学习中,树状数组的使用更为方便。
摘要由CSDN通过智能技术生成

数据结构-树状数组

树状数组是较堆功能更强大的能解决 RMQ 问题的数据结构 。

数组数组的前置知识:位运算

数组数组的功能:单点修改区间查询,区间修改单点查询(用差分)。

首先讲 l o w b i t ( x ) lowbit(x) lowbit(x),这是个位运算知识。表示 x x x 二进制下为 1 1 1 的最高位,如 l o w b i t ( ( 1110010 ) 2 ) = ( 10 ) 2 lowbit((1110010)_2)=(10)_2 lowbit((1110010)2)=(10)2 l o w b i t ( ( 110000 ) 2 ) = ( 10000 ) 2 lowbit((110000)_2)=(10000)_2 lowbit((110000)2)=(10000)2 C++ \texttt{C++} C++ 中的 x & − x x\&-x x&x 正好能达到求 l o w b i t ( x ) lowbit(x) lowbit(x) 的效果。

然后树状数组中的 c c c 数组是个有跳跃性的前缀和数组,它通过 l o w b i t ( ) lowbit() lowbit() 跳跃维护,然后通过 l o w b i t ( ) lowbit() lowbit() 跳跃取值。原理较为复杂,不必深究。但是它有如下性质:

1.每次在 x x x 位置上 + y +y +y 时,可以这样维护 c [ ] c[] c[]

void fix(Tree&t,int n,int x,int y){
	for(;x<=n;x+=low(x)) t.c[x]+=y;
} 

2.如下方法即可求出 Σ 1 x a [ i ] \Sigma_1^xa[i] Σ1xa[i]

int fsum(Tree&t,int x){
	int res=0;
	for(;x;x-=low(x)) res+=t.c[x];
	return res;
}

所以树状数组的空间复杂度为 O ( n ) O(n) O(n),时间复杂度为 O ( n log ⁡ n ) O(n\log n) O(nlogn)

主要操作大概就是这样,那么蒟蒻就放代码了:

namespace Sumtree{
	int low(int x){return x&(-x);}
	class Tree{
	public:
		int c[N];
		Tree(){memset(c,0,sizeof(c));}
	}st;
	void fix(Tree&t,int n,int x,int y){// 在x位置上+y
		for(;x<=n;x+=low(x)) t.c[x]+=y;
	} 
	int fsum(Tree&t,int x){//求出x的前缀和
		int res=0;
		for(;x;x-=low(x)) res+=t.c[x];
		return res;
	}
}using namespace Sumtree;

有了前缀数组后,就可以单点修改区间查询了。如果想区间修改单点查询,就把每个 a [ i ] = a [ i ] − a [ i − 1 ] a[i]=a[i]-a[i-1] a[i]=a[i]a[i1] 然后每次修改修改区间两端的值,单点查询的时候求和。

比起线段树,树状数组功能较弱,但代码短个几十行。而且后面学树套树的时候,数组数组会好套很多。

祝大家学习愉快!

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值