gwl999

博客园 首页 新随笔 联系 订阅 管理

5.11

离散化:

  • 离散化的本质,是映射,将间隔很大的点,映射到相邻的数组元素中。减少对空间的需求,也减少计算量。

  • 通过离散化可以处理哪种题目:给出的数组位置太大。

  • 例题:

    •  

       

  • 首先,通过这个区间和,可以想到的是前缀和相加减;

  • 其次,要求找某个位置的数,可以通过二分查找来找到想要的数

  • 具体做法思路:

 主要分为5大步:

  1. 读输入。将每次读入的x c push_back()到add中,将每次读入的位置x push_back()到alls中,将每次读入的l r push_back()到query中。

  2. 排序、去重。

  3. 通过遍历add,完成在离散化的数组映射到的a数组中进行加上c的操作(用到find函数)。

  4. 初始化s数组。

  5. 通过遍历query,完成求区间[l,r]的和。

  6. #include "algorithm"
    #include "iostream"
    #include "utility"//这个是pair的头文件
    #include "vector"
    using namespace std;
    const int N = 300010;
    typedef pair<int, int> PII;
    vector<int> alls;//这是用来记录离散化前后的vector
    vector<PII> add, query;//创建的pair数组用来记录初始输入,和输出的两个值
    //后面可以通过for(item:add/query)循环,通过item.first/second取值
    int a[N], s[N];//初始化vector里面值,和计算前缀和
    int find(int x) {
    //经典的二分,用来找到记录在离散化的vetor里的位置
       int l = 0, r = alls.size();
       while (l < r) {
           int mid = l + r >> 1;
           if (alls[mid] >= x)
               r = mid;
           else
               l = mid + 1;
       }
       return l + 1;
    //因为一般的离散都是从1开始计数的,如果是return l,那么初始的记录就是0;
    }
    vector<int>::iterator unique(vector<int>& a) {
    //用来去重的方法,c++中是自带的
       int j = 0;
       for (int i = 0; i < a.size(); i++)
           if (!i || a[i] != a[i - 1])
               a[j++] = a[i];
       // a[0] ~ a[j - 1] 所有a中不重复的数
    
       return a.begin() + j;
    }
    int main() {
       int n, m;
       cin >> n >> m;
       for (int i = 0; i < n; i++) {
           int x, c;
           cin >> x >> c;
           add.push_back({x, c});
    //而add是用来记录存储的位置和需要相加的值的
           alls.push_back(x);
           // x记录的是离散化前的位置,然后放入对应的vector里
       }
       for (int i = 0; i < m; i++) {
           int l, r;
           cin >> l >> r;
           query.push_back({l, r});
    //每次询问的值
           alls.push_back(l);
    //加入第一次问的位置
           alls.push_back(r);
    //加入第二个末尾的位置
       }
       sort(alls.begin(), alls.end());
       alls.erase(unique(alls), alls.end());
    //排序和去重操作,排序是因为我们需要二分操作,二分正常都是有序的
       for (auto item : add) {
    //从第一次的插入数据操作开始
           int x = find(item.first);
    //找到当时被插入的数
           a[x] += item.second;
    //被插入的数进行加上c;
       }
       for (int i = 1; i <= alls.size(); i++)
           s[i] = s[i - 1] + a[i];
       //将所有离散化后的数值计算,也是初始化
       for (auto item : query) {
           int l = find(item.first);
           //离散化后的位置
           int r = find(item.second);
           //离散化后的位置
           cout << s[r] - s[l - 1] << endl;
       }
       return 0;
    }
posted on   呓雫  阅读(80)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek “源神”启动!「GitHub 热点速览」
· 我与微信审核的“相爱相杀”看个人小程序副业
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 如何使用 Uni-app 实现视频聊天(源码,支持安卓、iOS)
· C# 集成 DeepSeek 模型实现 AI 私有化(本地部署与 API 调用教程)
点击右上角即可分享
微信分享提示