离散化区间和
题目
假定有一个无限长的数轴,数轴上每个坐标上的数都是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
输入样例:
1 | 3 3 |
输出样例:
1 | 8 |
解题思路
这道题看起来就感觉好像是赤裸裸的前缀和与差分。但是仔细看会发现,执行的操作不是对区间执行的,也就是说和差分没有关系,就是简单的前缀和。但是 看 x 的取值范围,到了10^9^了,一般数组可是存不下的,会报错。所以这里就要介绍离散化的思想了。
离散化
这道题操作的次数为 n 次,查询次数为 m 次,也就是说实际上被操作的数字,或者说我们需要讨论的数字,最多不超过 n+2m个。这个数组相当于是 3 10^5,相比于x的10^9小得多。所以我们现在就是需要进行离散化操作。
其实实现离散化也很简单,直接先输入时就存x,之后再去除重复的,剩下的数字就是待操作的。之后再遍历一次操作数组,执行操作,最后求前缀和的时候也只是求这个去重数组就行了。查询就是查询前缀和数组。
这相当于是一种映射。举个例子:我们只用:-10000,0,10000, 20000 。四个数字,但是分散得很开,直接存很浪费空间(开-10000~20000个位置来存),我们离散化之后就变成了4个位置。
离散化的方式有两种:
一种就是和哈希差不多的方式:先排序,然后指定映射下标。
例如上面的数组,排序后就变成了[0,1,2,3](因为我给出来的时候就是排好序了的)
这种处理的伪代码:
假设是对A数组离散化,C为待排序数组,L为最终映射结果。
1
2
3
4
5
6
7int C[MaxN], L[MaxN];
... // 函数中
memcpy(C, A, sizeof(A)); // 复制 A 数组
sort(C, C + n); // 排序
int l = unique(C, C + n) - C; // 去重
for (int i = 0; i < n; ++i)
L[i] = lower_bond(C, C+l, A[i]) - C + 1; //查找直接去重。(相同元素没必要存两遍)
像上面的例子,结果就应该为[-10000,0,10000,20000]
这种处理的伪代码(因为要用到STL函数,所以最好用vector,而不是普通数组):
对A数组离散化。
1
2sort(A.begin(), A.end()); // n 为A的长度
A.erase(unique(A,begin(), A.end()), A.end());
相关函数解释
后续为可能会发文章专门讲常用的STL函数,这里主要讲unique()
和erase()
unique()
它的功能是元素去重。即”删除”序列中所有相邻的重复元素(只保留一个)。此处的删除,并不是真的删除,而是指重复元素的位置被不重复的元素给占领了。由于它”删除”的是相邻的重复元素,所以在使用unique函数之前,一般都会将目标序列进行排序。
unique函数的去重过程实际上就是不停的把后面不重复的元素移到前面来,也可以说是用不重复的元素占领重复元素的位置。
函数原型:
1 | iterator unique(iterator it_1,iterator it_2); |
参数和返回值都是iterator
迭代器,可以理解为位置。参数就是带去重的初始位置和结束位置。返回值就是去重后,最后一个不重复元素的位置。
举例:
初始数组:[1,2,3,3,3,4,5,5,6,7,7,8] 注意,使用前一定要先排序好。
去重后数组:[1,2,3,4,5,6,7,8,3,3,5,7]
最终返回的就是 数字8的位置。
erase()
这个函数就是一个删除函数,有一点类似于remove()
它有三种函数原型:
处理字符串
1
string& erase(size_t pos = 0, size_t n);
例如:
str.erase(0,1)
删除字符串第一个字符;str.erase(0,3)
删除字符串前三个字符。处理任意集合
1
iterator erase(iterator pos);
删除pos位置的元素。注意,但传入参数为字符串的时候,它的参数是find(str)。也就是说先查找字符串在远串中的位置,然后再删除。
例如:
str.erase("c")
就是把原字符串中的字母c全删除掉;str.erase(str.first()+2)
就是把把第三个元素删除掉。注意不能直接写数字。
区间处理任意集合
1
iterator erase(iterator it_1, iterator it_2);
这个很好理解,就是将
it_1
到it_2
之间的元素删除掉。
上述的离散化中就是利用的第3个函数原型,将重复内容删除掉的。
解题代码
1 |
|