离散化

离散化

把下标非常大的序列映射成下标比较小的序列,并保证离散前后都是相对有序。有点压缩映射的意味在里面。使得映射后的序列非常的不稀疏!!!离散化的本质是映射,可以减少对空间的需求,减少离散化

做离散化的话 使用vector比较方便

思路:数组序列 排序+去重+二分

// 排序+去重
vector<int> alls; // 存储等待离散化的序列
sort(alls.begin(),alls.end());
alls.erase(unique(alls.begin(),alls.end()),alls.end()) // unique(alls.begin(),alls.end()) 返回的是已经去重后的子序列的尾结点

比如-1e9——1e9 长的数组 一般是映射到从1开始的自然数

离散化的概念比较简单,但是不好使用

去重unique轮子

// c++ unique函数的实现 本去重函数只能在排序后使用
vector<int> ::iterator unique(vector<int> &a){
  int j = 0;
  for(int i = 0; i<a.size();i++){
    if(!i || a[i]!=a[i-1]) // 第一个元素一定存起来
      a[j++] = a[i];
  }
  return a.begin()+j;
}

区间和案例:
假定有一个无限长的数轴,数轴上每个坐标上的数都是 0。
现在,我们首先进行 n 次操作,每次操作将某一位置 x 上的数加 c。
接下来,进行 m 次询问,每个询问包含两个整数 l 和 r,你需要求出在区间 [l,r] 之间的所有数的和。
这是一道区间和问题按理说应该使用前缀和的思想,但是麻烦是,本题数轴是无限长,若要开一个10^{9}级别的数组显然做不到,而且每个值得大小也是10^{9}级别。于是需要用到离散化的思想【个人觉得就是投影到小数组中】

离散化过程

将一个大数组映射到连续的小数组[1,2,3,4,5,6]由于需要使用到前缀和,所以是从1开始的。
Acwing 区间和


// 本题表面上是个区间和问题,但是实际中由于初始空间的范围是无限数轴,需要先使用离散化的思想,再进行前缀和求区间和
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
const int N = 10e5+10;

int n,m;
int a[N],s[N]; // a储存的是值,s储存的是前缀和
vector<int> all; // all储存的是所有的下标
vector<pair<int,int>> add,query; // 储存的是添加[index,value] 和 [index1,index2]


int find(int x) { //返回的是输入的坐标的离散化下标
    int l = 0, r = all.size() - 1;
    while (l < r) {
        int mid = l + r >> 1;
        if (all[mid] >= x) r = mid;
        else l = mid + 1;
    }
    return r + 1;   // 保证下标从1开始
}



int main(){
    
    // 1.前期 将需要的数据输入到合适的数组中
    cin >> n >> m;
    for(int i = 0;i<n;i++){
        int x,c;
        scanf("%d%d",&x,&c);
        add.push_back({x,c}); // 将组合对{x,c}传入add
        all.push_back(x);     // all储存的是全部的下标
    }  
    
    for(int i = 0;i<m;i++){
        int l,r;
        scanf("%d%d",&l,&r);
        query.push_back({l,r});
        all.push_back(l);
        all.push_back(r);
    }
    
    
    // 2.排序 去重
    sort(all.begin(),all.end());
    all.erase(unique(all.begin(),all.end()),all.end());
    
    for(auto item:add){
        int x = find(item.first);    // 这一段是灵魂代码  只是找到连续的下标
        a[x] += item.second;
    }
    
    // 3.前缀和    预处理 已经保证下标从1开始了
    for(int i = 1;i<=all.size();i++) s[i] = s[i-1] + a[i];
    
    for(auto item:query){
        int l = item.first;
        int r = item.second;
        printf("%d\n",s[r] - s[l-1]);
    }
    
    
    return 0;
}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容