算法竞赛进阶指南0x42 树状数组

本文详细介绍了树状数组的概念,以及如何利用树状数组进行单点修改和区间查询。内容涵盖树状数组的初始化、单点增加操作、区间最大值最小值维护、异或和维护,以及逆序对问题的解决。还提到了二维树状数组的应用。
摘要由CSDN通过智能技术生成

        我们在 0x01 节探讨过 lowbit 运算,并介绍了如何利用 lowbit 运算找出整数在二进制表示下所有等于 1 的位。类似地,给定一个整数 X,下面这段代码可以计算出区间 [1,X] 分成的 logX 个小区间。

 

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

        树状数组 (Binary Indexed Trees) 就是一种基于上诉思想的数据结构,其基本用途是维护序列的前缀和。 对于给定的序列 A,我们建立一个数组 C,其中 C[X] 保存序列 A 的区间  [ X - lowbit(X) + 1, X] 中所有数的和。 

         事实上,数组C可以看作一个如下图的树形结构。每个内部节点保存以它为根的子树中所有叶节点的和。每个内节点的子节点个数等于 lowbit(X) 的位数,除树根外,每个内部节点的父节点是 t[ X + lowbit(X) ],树的深度为 logN。

        如果 N 不是2的整次幂,那么树状数组就是一个具有同样性质的森林结构。

在这里插入图片描述

        树状数组支持的基本操作有两个,第一个操作是查询前缀和,即序列 A 第 1 -> X 个数的和。按照我们刚才提出的方法,应该求出 X 的二进制表示中每个等于 1 的位,把 [1,X] 分成 logN 个小区间,而每个小区间的区间和都已经保存在数组 C 中。所有,我们可以在O(logN)的时间内查询前缀和。

int /*long long*/ ask(int x) {
	int /*long long */ ans = 0;
	for (; x; x -= x & -x) {
		ans += c[x];
	}
	return ans;
}

        当然,若要查询序列 A 的区间 [L,R] 中所有数的和, 只需计算 ask(R) - ask(L - 1)。

        树状数组支持的第二个基本操作是单点增加,意思是给序列中的一个数 A[X] 加上 y,同时正确维护序列的前缀和。根据上面给出的树形结构和它的性质,只有节点 C[X] 极其所以祖先节点保存的 "区间和" 包含 A[X],而任意一个节点的祖先至多只有 logN 个,我们逐一对他们的 C 值进行更新即可。下面的代码在 O(logN) 时间内执行单点增加操作。

void add(int x, int y) {
    for (; x <= n; x += lowbit(x)) c[x] += y
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值