数组上的询问【前缀和】

博客内容介绍了如何使用前缀和技巧优化数组区间求和问题。通过预先计算数组的累积和,可以高效地回答区间内元素和是否为0的问题,从而避免暴力模拟。文章通过实例解释了前缀和的概念,并提供了相关代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Description

给出一个有N个元素的数组A,元素的值要么是1,要么是-1。

给出M次询问,每次询问的格式为:L, R,表示求S = A[L] + A[L+1] + ... + A[R]的值。若S 的值为0,输出"YES",否则输出"NO"。


Input
第1行:两个整数N和M(1<=N, M <=100000)
        第2行:N个空格分开的整数,表示数组的各个元素,保证只含1和-1
        接下来M行,每行两个整数L,R(1 <=L <= R <=N),表示每个询问的左右端点
Output
### 树状数组前缀和的概念及联系 #### 一、树状数组的基础概念 树状数组(Binary Indexed Tree 或 Fenwick Tree)是一种用于高效计算动态数组前缀和的数据结构。其核心思想是通过一种特殊的数组存储方式来支持快速的单点更新以及范围查询操作[^2]。 树状数组的核心在于 `lowbit` 函数的应用,该函数可以提取一个整数最低位上的1及其后续0组成的数值。例如对于数字8 (二进制表示为1000),`lowbit(8)` 返回的是8本身;而对于9 (二进制表示为1001),返回的结果则是1。这种特性使得我们可以构建一棵隐式的树形结构,从而实现高效的前缀和查询功能[^1]。 #### 二、前缀和的基本定义 前缀和是指给定一个数组A,它的第i项前缀和S[i]等于从首元素到当前索引位置所有元素之和即 \( S[i]=\sum_{j=0}^{i}{A[j]} \)[^3]。如果仅需一次性获取整个数组前缀和,则可以通过简单的线性扫描完成这一任务。然而当面对频繁修改或者多次询问不同区间的累积值时,朴素的方法效率低下,此时引入更高级别的工具如树状数组就显得尤为重要了。 #### 三、树状数组的操作方法 ##### 单点更新 假设我们需要改变原数组中的某个特定值a[x], 那么相应地也需要调整BIT(bit[]代表树状数组) 中涉及的所有节点: \[ bit[k]+=delta,\quad k+=k&(-k)\] 这里\( delta=a'[x]-a[x]\), 表示新旧两个版本之间差异部分; 同样采用循环直到超出边界为止. ##### 区间查询 为了得到任意指定下标的累计总和s[y]: \[ s[y]=\text{getSum}(y)=\sum_{i=1}^{y}\text{bit}[i].\] 具体做法是从目标坐标出发逐步回溯父结点直至起点处累加沿途经过的各项贡献值得到最后结果. \[ res += bit[y]; y -= lowbit(y);\] 以上两步构成了基本框架, 可以满足大多数场景需求.[^4] #### 四、区别与联系 尽管两者都服务于相同目的——加速针对连续片段内的汇总运算过程,但它们各自适用场合有所侧重: - **简单静态环境**: 如果只是单纯读取固定不变的一组数据并反复调用其中某些片断的信息的话,那么预处理好全局性的prefix_sum即可胜任工作。 - **动态变化条件下**: 当面临不断发生更改的情况比如增加删除替换等动作影响原始资料分布形态之时,则应该优先考虑运用更为灵活强大的tree-based solution也就是本文介绍过的binary indexed tree形式来进行管理控制。因为后者不仅能够很好地兼顾速度表现还能适应更加复杂的业务逻辑要求。 ```python def lowbit(x): return x & (-x) class BITree: def __init__(self, size): self.size = size self.tree = [0]*(size+1) def update(self,index,delta): while index<=self.size: self.tree[index] += delta index += lowbit(index) def getPrefixSum(self,index): result = 0 while index>0: result += self.tree[index] index -= lowbit(index) return result ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值