高级前缀和
高级前缀和实现
在处理大范围坐标的区间求和时,可以使用离散化技术和前缀和结合来提高效率。本文将介绍如何使用C++实现这一方法。
题目
假定有一个无限长的数轴,数轴上每个坐标都是0。
现在,我们首先进行n次操作,每次操作将某一位置x上的数加c。
接下来,进行m次询问,每个询问包含两个整数l和r,你需要求出在区间[l,r]之间所有数的和。
输入格式
第一行包含两个整数n、m。
接下来n行,每行包括两个整数x和c。
再接下来里m行,每行包括两个整数l和r。
输出格式
共m行,每行输入一个询问中所求得区间内数字和。
代码实现
以下是一个实现高级前缀和的完整C++代码示例:
1 | #include<iostream> |
示例输入输出
以下是一些示例输入和对应的输出,帮助理解代码的工作原理。
示例 1
输入:
输出:
示例 2
输入:
输出:
示例 3
输入:
输出:
代码说明
输入处理:
- 使用
cin
函数读取操作数m
和查询数n
。 - 读取操作和查询的坐标,存储在对应的向量中,并记录所有需要的坐标。
离散化和前缀和实现:
- 通过排序和去重对坐标进行离散化。
- 使用离散化后的坐标构造前缀和数组。
主函数逻辑:
- 读取输入数据并进行离散化处理。
- 构造前缀和数组,并处理每个查询,输出对应的区间和。
当然可以。下面是一个具体的例子以及按照代码处理流程的解释:
输入示例
假设输入如下:
输入解释
- 第1行:
3 2
表示有3个添加操作和2个查询操作。 - 第2-4行:
1 5
,2 6
,3 7
是3个添加操作,表示在坐标1加上5,在坐标2加上6,在坐标3加上7。 - 第5-6行:
1 3
,2 3
是2个查询操作,分别查询区间[1, 3]
和[2, 3]
的和。
按照代码处理流程
读取输入并存储操作:
m = 3
,n = 2
。1
2
3
4
5
6for (int i = 0; i < m; i++) {
int b, c;
cin >> b >> c;
alls.push_back(b);
add.push_back({b, c});
}处理添加操作,将坐标
b
存入alls
,并将操作(b, c)
存入add
。alls = [1, 2, 3]
,
add = [(1, 5), (2, 6), (3, 7)]
。1
2
3
4
5
6
7for (int i = 0; i < n; i++) {
int b, c;
cin >> b >> c;
alls.push_back(b);
alls.push_back(c);
question.push_back({b, c});
}处理查询操作,将区间起点和终点
b, c
存入alls
,并将操作(b, c)
存入question
。alls = [1, 2, 3, 1, 3, 2, 3]
,
question = [(1, 3), (2, 3)]
。离散化处理:
对
alls
进行排序和去重。alls = [1, 2, 3]
。执行添加操作:
将添加操作应用到离散化后的数组
a
中。find(1) = 1
,find(2) = 2
,find(3) = 3
。更新后
a
数组的变化:
a = [0, 5, 6, 7]
。构建前缀和数组:
构建前缀和数组
s
。前缀和数组
s
:
s = [0, 5, 11, 18]
。处理查询操作并输出结果:
1
2
3
4
5for (auto x : question) {
int h = find(x.first);
int t = find(x.second);
cout << s[t] - s[h - 1] << " ";
}处理查询操作并输出结果。
- 查询区间
[1, 3]
:
find(1) = 1
,find(3) = 3
,
结果:s[3] - s[0] = 18 - 0 = 18
。 - 查询区间
[2, 3]
:
find(2) = 2
,find(3) = 3
,
结果:s[3] - s[1] = 18 - 5 = 13
。
- 查询区间
最终输出
总结
通过这个例子,我们可以看到代码是如何处理添加和查询操作的。代码通过离散化技术将原始坐标映射到较小的连续整数范围,从而在固定大小的数组上执行操作,这显著提高了处理效率。