摘要:
离散化模板题。
题目
假定有一个无限长的数轴,数轴上每个坐标上的数都是 $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. 区间和