一:有序的离散化

image.png

  • 3*10^5是用到的坐标数量
  • n次操作,最多用到n个坐标的数
  • m次查询最多用到2m个坐标的数,因为一次查询需要访问两个数,总的加起来一共3*10^5,这也是作为离散后数组的大小

image.png

思路就是把要求的区间的数放在一个数组中,利用前面的前缀和的思想进行求解。因为l,r的范围是10^9,所以不能直接按照前缀和的方式,开数组不能开出那么大的数组来。
image.png

离散化用vector进行
unique() 返回的迭代器作为 text 成员函数 erase() 的第一个参数,而且它会指向被移除的第一个字符。erase() 的第二个参数是 text 的结束迭代器,因此在没有重复元素的新字符串之后的所有字符都会被移除。

auto的作用:C++11中 也拥有了类似的功能:auto 类型推导
image.png

  • 注意加法的x和查询的l, r全部都可以是负数,也是使用离散化不能直接使用前缀和的原因。
  1. #include <iostream>
  2. #include <vector>
  3. #include <algorithm>
  4. using namespace std;
  5. typedef pair<int, int> PII; // pair可以理解为一种结构体,因为vector不能存储多个值,pair里面有俩属性,first,second
  6. const int N = 3e5 + 10; // 为什么是3,看前面的图文分析
  7. int n, m; // n是加操作次数,m是查询次数
  8. int a[N], s[N];
  9. vector<PII> add, query; // 因为每次加和查询操作都是两个数,输入的时候需要保存
  10. vector<int> alls; // 把上面加操作和查询操作的所有坐标/下标全部存储下来
  11. /*
  12. 已经把所有操作的下标存在了一个alls的vector数组中,当实际进行加的操作,需要对a进行操作,a的下
  13. 标是离散化的,也就是对alls数组二分查找,定位alls找到对应值的下标,这个就是a的下标,返回以后,
  14. a[x] += c即可。
  15. */
  16. int find(int x) {
  17. int l = 0, r = alls.size() - 1;
  18. while (l < r) {
  19. int mid = l + r >> 1;
  20. if (alls[mid] >= x) r = mid;
  21. else l = mid + 1;
  22. }
  23. return l + 1;
  24. }
  25. int main() {
  26. scanf("%d%d", &n, &m);
  27. // 不所有的操作保存在add的同时,操作过的下表/坐标全部存到alls中,为后面二分准备
  28. for (int i = 0; i < n; i++) {
  29. int x, c;
  30. cin >> x >> c;
  31. add.push_back({x, c});
  32. alls.push_back(x);
  33. }
  34. // 把所有的查过的坐标都保存下来
  35. for (int i = 0; i < m; i++) {
  36. int l , r;
  37. cin >> l >> r;
  38. query.push_back({l, r});
  39. alls.push_back(l);
  40. alls.push_back(r);
  41. }
  42. sort(alls.begin(), alls.end()); // sort的目的让alls里面的坐标全部从小到大
  43. alls.erase(unique(alls.begin(), alls.end()), alls.end()); //删除所有的重复元素,保证所有访问的坐标从小到大并且不重复
  44. for (auto item : add) {
  45. int x = find(item.first); // 真正执行加法操作
  46. a[x] += item.second;
  47. }
  48. for (int i = 1; i <= alls.size(); i++) {
  49. s[i] = s[i - 1] + a[i];
  50. }
  51. for (auto item : query) {
  52. int l = find(item.first);
  53. int r = find(item.second);
  54. cout << s[r] - s[l - 1] << endl;
  55. }
  56. return 0;
  57. }