• 离散化(保序)


    目录

    概念

    可能出现的问题

    分类

    1.保序

     离散化模板( https://www.acwing.com/blog/content/277/)

     例题:区间和

    思路

    代码

    2.不保序


    概念

            给定一系列要为坐标的值,可能很大,1 到 10e9  ,总不能开一个10e9的数组吧,就要涉及到离散化,将10e5个数(大小在10e9之内)映射到1~10e5,这个映射的过程就叫离散化。

    可能出现的问题

            1.有重复元素,需要去重。

            2.如何算出a[ i ] 离散后的值。

    分类

    1.保序

    排序判重+二分

     离散化模板( https://www.acwing.com/blog/content/277/

    1. vector<int> alls; // 存储所有待离散化的值
    2. sort(alls.begin(), alls.end()); // 将所有值排序
    3. alls.erase(unique(alls.begin(), alls.end()), alls.end()); // 去掉重复元素
    4. // 二分求出x对应的离散化的值
    5. int find(int x) // 找到第一个大于等于x的位置
    6. {
    7. int l = 0, r = alls.size() - 1;
    8. while (l < r)
    9. {
    10. int mid = l + r >> 1;
    11. if (alls[mid] >= x) r = mid;
    12. else l = mid + 1;
    13. }
    14. return r + 1; // 映射到1, 2, ...n 不加1,从0开始映射
    15. }

     例题:区间和

    假定有一个无限长的数轴,数轴上每个坐标上的数都是 0。现在,我们首先进行 n次操作,每次操作将某一位置 x 上的数加 c。接下来,进行 m次询问,每个询问包含两个整数 l 和 r,你需要求出在区间 [l,r]之间的所有数的和。

    输入格式

    第一行包含两个整数 n和 m。接下来 n行,每行包含两个整数 x 和 c。再接下来 m行,每行包含两个整数 l 和 r。

    输出格式

    共 m行,每行输出一个询问中所求的区间内数字和。

    数据范围

    −10e9 ≤ x ≤ 10e9,
    1≤n,m≤10e5,
    −10e9 ≤ l ≤ r ≤ 10e9,
    −10000 ≤ c ≤ 10000

    输入样例:

    1. 3 3
    2. 1 2
    3. 3 6
    4. 7 5
    5. 1 3
    6. 4 6
    7. 7 8

    输出样例:

    1. 8
    2. 0
    3. 5

    思路

            下标范围很大,但我们只用到n+m个(3*10e5);

            由前缀和思想,我们可以很快求出某一区间的值,要用前缀和,那么离散化后的数组下标要从1开始。所以二分返回结果要加1.

            要在某一个下标加上c的话,就算出它离散后的下标,并在那个位置加c;

            比如要求L,R之间的数,我们算出离散化的坐标LK,RK后,求LK,RK之间的和就可以了。

    代码

    1. #include
    2. #include
    3. using namespace std;
    4. const int N = 300010;
    5. int n, m;
    6. int a[N];//要存的数
    7. int s[N];//前缀和
    8. vector<int> alls;//存所有要离散化的值
    9. typedef pair<int, int> PII;
    10. vector add, query;
    11. int find(int x) {
    12. int l = 0, r = alls.size() - 1;
    13. while (l < r) {
    14. int mid = l + r >> 1;
    15. if (alls[mid] >= x)r = mid;
    16. else l = mid + 1;
    17. }
    18. return r + 1;
    19. }
    20. int main() {
    21. //将所有数读进来,所有用到的下标离散化
    22. cin >> n >> m;
    23. for (int i = 0; i < n; i++) {
    24. int x, c;
    25. cin >> x >> c;
    26. add.push_back({ x, c });
    27. alls.push_back(x);
    28. }
    29. for (int i = 0; i < m; i++) {
    30. int l, r;
    31. cin >> l >> r;
    32. query.push_back({ l,r });
    33. alls.push_back(l);
    34. alls.push_back(r);
    35. }
    36. //放好以后开始去重
    37. sort(alls.begin(), alls.end());
    38. alls.erase(unique(alls.begin(), alls.end()), alls.end());
    39. for (auto item : add) {
    40. int x = find(item.first);
    41. a[x] += item.second;
    42. }
    43. //预处理前缀和;
    44. for (int i = 1; i <= alls.size(); i++) s[i] = s[i - 1] + a[i];
    45. //处理询问
    46. for (auto item : query) {
    47. int l = find(item.first), r = find(item.second);
    48. cout << s[r] - s[l - 1] << endl;
    49. }
    50. return 0;
    51. }

    2.不保序

     map或者hash表

    https://blog.csdn.net/qq_59183443/article/details/127520112?csdn_share_tail=%7B%22type%22%3A%22blog%22%2C%22rType%22%3A%22article%22%2C%22rId%22%3A%22127520112%22%2C%22source%22%3A%22qq_59183443%22%7D

  • 相关阅读:
    分布式事务解决方案Seata
    软件工程与计算(十八)代码设计
    【技术积累】Vue.js中的核心知识【二】
    从字节码角度带你彻底理解i++与++i
    Java基础面试题
    选择排名靠前的期货公司开户
    Day10—Spark SQL基础
    联想Thinkbook Ubuntu18.04 安装nvidia显卡驱动
    JavaScript 基础知识使用教程
    数据中心的能耗焦虑, 到底有没有最优解?
  • 原文地址:https://blog.csdn.net/qq_59183443/article/details/126963067