这段代码实现了一个基于前缀和的区间和查询功能。它的核心思想是通过预先计算一个前缀和数组 s
,使得每次查询某个区间的和时,可以在常数时间内完成。以下是代码的详细思路解析:
假设有一个数组 a
,长度为 n
,我们需要多次查询某个区间 [l, r]
内所有元素的和。直接计算区间和的方法是遍历区间 [l, r]
并累加,但这会导致每次查询的时间复杂度为 O(n),效率较低。为了优化查询效率,可以使用前缀和技术。
前缀和数组 s
是一个辅助数组,其中 s[i]
表示数组 a
从第 1 个元素到第 i
个元素的累加和,即:
cpp复制
s[i] = a[1] + a[2] + ... + a[i]
通过前缀和数组,可以快速计算任意区间 [l, r]
的和:
cpp复制
sum[l, r] = s[r] - s[l - 1]
这里的关键是利用了前缀和的性质:s[r]
是从 a[1]
到 a[r]
的累加和,s[l - 1]
是从 a[1]
到 a[l - 1]
的累加和,因此它们的差值就是区间 [l, r]
的和。
cpp复制
cin >> n >> m; // 输入数组长度 n 和查询次数 m
for (int i = 1; i <= n; i++) cin >> a[i]; // 输入数组 a
用户输入数组的长度 n
和查询次数 m
。
接着输入数组 a
的每个元素。数组 a
的索引从 1 开始,方便后续计算。
cpp复制
s[0] = 0; // 初始化 s[0] 为 0
for (int i = 1; i <= n; i++)
s[i] = s[i - 1] + a[i]; // s[i] 是从 a[1] 到 a[i] 的累加和
初始化 s[0] = 0
,表示从第 1 个元素之前的累加和为 0。
使用循环计算前缀和数组 s
:
s[i]
的值等于 s[i - 1]
(前一个前缀和)加上当前元素 a[i]
。
这样,s[i]
就存储了从 a[1]
到 a[i]
的累加和。
cpp复制
while (m--)
{
int l, r;
cin >> l >> r; // 输入查询区间 [l, r]
cout << s[r] - s[l - 1] << endl; // 输出区间和
}
用户输入查询区间 [l, r]
。
利用前缀和数组快速计算区间和:
区间 [l, r]
的和等于 s[r] - s[l - 1]
。
这里利用了前缀和的性质,计算结果的时间复杂度为 O(1)。
输出查询结果。
时间复杂度:
计算前缀和数组的时间复杂度为 O(n)。
每次查询的时间复杂度为 O(1)。
总时间复杂度为 O(n + m),其中 n
是数组长度,m
是查询次数。
空间复杂度:
使用了一个额外的前缀和数组 s
,空间复杂度为 O(n)。
plaintext复制
5 3
1 2 3 4 5
1 3
2 4
1 5
输入数组长度 n = 5
和查询次数 m = 3
。
输入数组 a = [1, 2, 3, 4, 5]
。
计算前缀和数组 s
:
s[0] = 0
s[1] = 1
s[2] = 3
s[3] = 6
s[4] = 10
s[5] = 15
处理查询:
查询 [1, 3]
的和:s[3] - s[0] = 6
查询 [2, 4]
的和:s[4] - s[1] = 9
查询 [1, 5]
的和:s[5] - s[0] = 15
plaintext复制
6
9
15
这段代码的核心思路是通过前缀和技术,将区间和查询的时间复杂度从 O(n) 优化到 O(1)。通过预先计算一个前缀和数组 s
,可以快速完成多次区间和查询,适用于需要频繁查询区间和的场景。
完整代码
#include
using namespace std;
const int N = 1e5 + 10;
int n, m;
int a[N], s[N]; // a 存储原始数组,s 存储前缀和
int main()
{
cin >> n >> m; // 输入数组长度 n 和查询次数 m
for (int i = 1; i <= n; i++) cin >> a[i]; // 输入数组 a
// 计算前缀和数组 s
s[0] = 0; // 初始化 s[0] 为 0
for (int i = 1; i <= n; i++)
s[i] = s[i - 1] + a[i]; // s[i] 是从 a[1] 到 a[i] 的累加和
// 处理 m 次查询
while (m--)
{
int l, r;
cin >> l >> r; // 输入查询区间 [l, r]
cout << s[r] - s[l - 1] << endl; // 输出区间和
}
return 0;
}