树状数组和线段树是两种在计算机科学中用于高效处理区间或段上数据更新与查询的数据结构。它们主要用于动态维护一个序列上的前缀和(区间和)问题,即在序列上进行插入、删除和查询操作时保持区间的和。
**树状数组(Cumulative Array, 也称 Fenwick Tree)**
树状数组是一种简洁的数据结构,它的主要思想是对每个位置i存储从i到当前位置的累加值。这种结构可以高效地完成单点修改和区间查询操作。以下是树状数组的基本操作:
1. **查询代码**:
查询区间[1, x]的和可以使用上述的`sum(int x)`函数。这个函数通过不断地减去当前元素的低二进制位来向上移动到父节点,每次累加对应的C[i]值,直到x变为0。
2. **修改代码**:
使用`change(int i, int k)`函数可以实现对位置i的数值增加k。这个函数同样利用了低二进制位的性质,逐级向上更新C[i]的值,直到i超出序列长度n。
3. **lowbit(x)求法**:
`lowbit(x)`函数计算x的最低位为1的二进制位,可以使用x与-x的按位与操作得到。这是因为在补码表示下,负数的最低位为1,正数的最低位为0,所以x与-x的结果就是x的最低位为1的二进制位。
4. **二维树状数组**:
对于二维情况,可以扩展树状数组来处理矩阵中的区间和。`update(int x, int y, int z)`函数用于更新矩阵中由(x, y)至(x, m)和由(x, y)至(n, y)的矩形区域,而`sum(int x, int y)`函数则用于查询这个矩形区域的和。
**线段树 Segment Tree**
线段树是一种完全二叉树,其每个节点代表一个区间。线段树的主要优势在于它可以支持区间更新和区间查询,且效率高。
1. **node结构体**:
线段树的每个节点通常包含两个子节点(左子树和右子树)以及一个区间和,用于保存子区间的信息。
2. **建树**:
建立线段树的过程通常是从底向上,先初始化所有叶子节点,然后逐层向上合并子节点的信息,直到根节点。
3. **单点修改**:
单点修改通常涉及到找到该点所在的叶节点,然后从该节点向上更新到根节点,以反映修改后的区间和。
4. **查询**:
查询区间[i, j]的和时,从根节点开始,根据区间是否包含在当前节点的子区间内,选择合适的孩子节点递归查询,直到到达叶节点,最后将沿途经过的节点的区间和累加起来。
树状数组和线段树都是在数据结构与算法领域中非常重要的工具,它们在处理动态区间信息时提供了高效的解决方案,广泛应用于各种在线算法和数据处理问题中。虽然它们的实现原理有所不同,但在许多实际应用中都能找到各自的优势。