摘要:
离散化模板题。
题目
假定有一个无限长的数轴,数轴上每个坐标上的数都是 $0$。
现在,我们首先进行 $n$ 次操作,每次操作将某一位置 $x$ 上的数加 $c$。
接下来,进行 $m$ 次询问,每个询问包含两个整数 $l$ 和 $r$,你需要求出在区间 $[l, r]$ 之间的所有数的和。
输入格式
第一行包含两个整数 $n$ 和 $m$。
接下来 $n$ 行,每行包含两个整数 $x$ 和 $c$。
再接下里 $m$ 行,每行包含两个整数 $l$ 和 $r$。
输出格式
共 $m$ 行,每行输出一个询问中所求的区间内数字和。
数据范围
- $−10^9≤x≤10^9$,
- $1≤n,m≤10^5$,
- $−10^9≤l≤r≤10^9$,
- $−10000≤c≤10000$
输入样例:
3 3
1 2
3 6
7 5
1 3
4 6
7 8
输出样例:
8
0
5
离散化
1 |
|
add下标最多1e5个,query下标最多2e5个。当最极端的情况出现时,下标总数可达到3e5。
- 待离散化数组,存放
add下标和query下标。
- 为了方便求前缀和,将
add每一位映射到a数组向右偏移一位的位置(从1开始)。
add数据输入。
query数据输入。
- 排序为了方便二分查找映射下标。
- 去重为了让所有待离散化数据一一映射自己的下标。
- 处理映射数组,所有
add下标对应统统加上相应的数;所有query下标对应默认为0。
- 求前缀和数组。我们知道求前缀和数组需要从
1开始取,但是这里为什么 可以 从1开始遍历呢?因为alls数组是从0开始记录的,find方法将坐标映射到下标时已经向右偏移了一位,所以a数组值 $> 0$ 的位置一定是 $> 0$ 的。另外注意到这里为什么要用alls.size()呢,那是因为离散化操作将所有的alls数组中的值全部映射到了a数组中,且前缀和数组长度一定和alls一样长。
- 输出查询
- 当数组范围大的时候一定要在
main()函数外面开数组,因为在这里开数组其内存会被分配在数据区(堆),而在main()内开数组其内存你会被分配在代码区,数据量大的话会出错。
注意,由于vector数组自身的属性,此时是从 $0$ 开始记录的。由于我们要构建前缀和数组,在处理 a 数组时要从 $1$ 开始构建,所以在通过 find 方法找坐标下标时,要整体向右偏移一位。
现在我们尝试描述一下a数组:a 数组存放着 alls 数组排序去重之后的所有值的下标,注意这里的下标是 alls 数组的。因为 alls 数组中存放着坐标轴上 add 操作和 query 操作涉及到的坐标,所以 a 数组中部分值为非零部分为零。非零的部分是 add 操作增加的数,零的部分包含 query 操作对应的没什么意义的 0 和剩下的一些留空数组元素 0.
本质上,alls 数组可以看成是一组映射关系。将可能取到极大或极小但数量有限的坐标和数组下标对应起来。其中,alls 数组的下标对应映射的结果,alls 数组的值对应原坐标轴的坐标。此后我们将 alls 数组的下标单独拿出来对应 a 数组,alls 数组的值单独拿出来放在 a 数组对应的下标处。这样就完成了离散化。
原题链接: AcWing 802. 区间和