📚 算法笔记:B3612 求区间和 (前缀和基础)
1. 题目简述
给定一个长度为 NNN 的数列和 MMM 次询问。每次询问给定区间 [l,r][l, r][l,r],要求快速输出该区间内所有元素的和。数据范围 N,M≤105N, M \le 10^5N,M≤105。
2. 核心代码 (C++ 实现)
c++
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
// 全局变量:Sum[i] 表示前 i 项的和
// 数组开大一点(100005)防止越界,且全局变量自动初始化为 0
ll Sum[100005] = {0};
void solve()
{
ll N, M;
// 1. 读取数组长度并进行安全检查
if (!(cin >> N)) return;
// 2. 预处理:求前 n 项和并存入 Sum 数组
for (int i = 1; i <= N; i++)
{
int val;
cin >> val;
// 核心递推式:S[i] = a[i] + S[i-1]
Sum[i] = val + Sum[i-1];
}
// 3. 处理 M 次查询
cin >> M;
for (int i = 1; i <= M; i++)
{
int fir, sec;
cin >> fir >> sec;
// 核心区间公式:Sum[r] - Sum[l - 1]
ll output = Sum[sec] - Sum[fir - 1];
cout << output << endl;
}
}
int main()
{
// 蓝桥杯/竞赛必备:加速 I/O 性能
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
solve();
return 0;
}
3. 核心考点与注意事项
🔍 核心考点
-
前缀和原理 :利用预处理 O(N)O(N)O(N) 的时间计算出
Sum数组,使得后续每次区间查询都能在 O(1)O(1)O(1) 时间内完成。
-
区间和公式 :对于区间 [l,r][l, r][l,r],其和为 Sum[r]−Sum[l−1]Sum[r] - Sum[l-1]Sum[r]−Sum[l−1]。
-
坐标偏移 :前缀和通常从下标 1 开始存储。这样处理 l=1l=1l=1 的情况时,会用到 Sum[0]Sum[0]Sum[0],而 Sum[0]Sum[0]Sum[0] 默认为 0,逻辑非常自然。
⚠️ 注意事项
- 防止 TLE(超时) :当 NNN 和 MMM 都达到 10510^5105 时,普通的
for循环嵌套查询会达到 101010^{10}1010 次运算,必须使用前缀和优化。 - 数据类型 :虽然本题
int可能溢出不明显,但在求累加和的题目中,习惯性使用long long存储Sum数组可以避免很多隐蔽的 Bug。 - 数组大小 :数组定义应略大于题目要求的上限(如 10510^5105 写成 100005100005100005 不可以写成 1e51e51e5),防止越界。
4. 易错点回顾 (My Mistakes)
-
公式记忆偏差 :最初误写为
Sum[sec] - Sum[fir]。纠正: 减去Sum[fir]会把左端点的值也减掉,必须减去Sum[fir - 1]。 -
动态数组定义错误 :尝试用变量
N直接定义数组Sum[N]。纠正: 在 C++ 中应使用常量或足够大的全局数组。