数据结构 - 树状数组

树状数组:区间查询 + 单点增加

概念:

一个基于二进制思想的数据结构,这可以能够使求前缀和和修改的时间复杂度控制在nlogm。

原理:

把一个[1,x]的区间划分为log(x)个小区间,并用tr[x]保存每个区间[x - lowbit(x) + 1,x]中所有数的和

用途:总的来说,就是求区间和的问题

可以在O(log N)的时间内进行 区间查询单点增加

满足的性质:

  1. 每个内部节点 tr[x] 保存以它为根节点的子树中所有叶节点的和
  2. 每个内部节点 tr[x] 的子节点个数等于lowbit(x)的位数
  3. 除树根外,每个内部节点 tr[x] 的父节点是 tr[x + lowbit(x)]
  4. 树的深度为O(log N)
    如果N不是2的整次幂,那么数组数组就是具有同样性质的森林结构

在附一张图解:(扣来的)

在这里插入图片描述

实现:

1. 查询前缀和
int ask(int x)
{
	int ans = 0;
	for(int i = x; i; i -= lowbit(x)) ans += tr[x]; // 
	return ans;
}

在这里插入图片描述

2. 单点增加(给序列中的一个数a[x]加上y)
void add(int x, int y)
{
	for(int i = x; x <= n; i += lowbit(x)) tr[x] += y;
}

在这里插入图片描述

lowbit:能够找到一个数在二进制表现下最后一位1,
lowbit的实现:

int lowbit(int x)
{
	return x & -x;
}

例题:Acwing - 241. 楼兰图腾

树状数组的扩展1:区间增加 + 单点查询

用差分来维护树状数组 可以巧妙的把区间增加单点查询 变为 区间查询单点增加
例题:AcWing 242. 一个简单的整数问题

树状数组的扩展2:区间增加 + 区间查询

首先还是用差分来建立树状数组b[ ],

区间增加

因为是差分,所以只要在b[l] + d, b[r + 1] - d即可

区间查询

∑ i = 0 n x i \sum_{i = 0}^{n} x_i i=0nxi
假设求1 ~ n的区间所有的和: ∑ i = 1 n a i = ∑ i = 1 n ∑ j = 1 i b i \sum_{i_ = 1}^{n} a_i = \sum_{i = 1}^{n} \sum_{j = 1}^{i} b_i i=1nai=i=1nj=1ibi
图解:
在这里插入图片描述
有上图可知sum = ( b 1 b_{1} b1 + b 2 b_{2} b2 + … + b n b_{n} bn) * (n + 1) - ( b 1 b_{1} b1 + 2 * b 2 b_{2} b2 + 3 * b 3 b_{3} b3 + … + n * b n b_{n} bn)
所以我们可以建2个树状数组来维护:
tr1[]来维护b[i]的前缀和
tr2[]来维护b[i] * i的前缀和
这样就可以实现区间增加和区间查询了
例题:AcWing 243. 一个简单的整数问题2

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值