页面正在赶来的路上……

基础算法——离散化


离散化

参考知乎文章:算法学习笔记(19): 离散化 - 知乎 (zhihu.com)

1. 离散化定义

离散化,就是当我们只关心数据的大小关系时,用排名代替原数据进行处理的一种预处理方法。离散化本质上是一种哈希,它在保持原序列大小关系的前提下把其映射成正整数。当原数据很大或含有负数、小数时,难以表示为数组下标,一些算法和数据结构(如BIT)无法运作,这时我们就可以考虑将其离散化。

image-20230915214921191

值域很大,但是值很稀疏,每次用到的只有它们的相对关系

2. 算法模板

vector alls; // 存储所有待离散化的值
sort(alls.begin(), alls.end()); // 将所有值排序
alls.erase(unique(alls.begin(), alls.end()), alls.end());   // 去掉重复元素

// 二分求出x对应的离散化的值
int find(int x) // 找到第一个大于等于x的位置
{
    int l = 0, r = alls.size() - 1;
    while (l < r)
    {
        int mid = l + r >> 1;
        if (alls[mid] >= x) r = mid;
        else l = mid + 1;
    }
    return r + 1; // 映射到1, 2, ...n
}

3. 例题与题解

原题链接:802. 区间和 - AcWing题库

假定有一个无限长的数轴,数轴上每个坐标上的数都是 00。

现在,我们首先进行 n 次操作,每次操作将某一位置 x 上的数加 c 。

接下来,进行 m 次询问,每个询问包含两个整数 l 和 r,你需要求出在区间 $[l,r]$$之间的所有数的和。

输入格式

第一行包含两个整数 n 和 m。

接下来 n 行,每行包含两个整数 x 和 c。

再接下来 m 行,每行包含两个整数 l 和 r。

输出格式

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

数据范围
$$
-109<x<109\
1≤n,m≤10^5\
−109≤l≤r≤109\
−10000≤c≤10000\
$$
输入样例

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

输出样例

8
0
5

题解与代码:AcWing 802. 画个图辅助理解~ - AcWing

C++ 代码

#include 
#include 
#include 

using namespace std;
const int N = 300010; //n次插入和m次查询相关数据量的上界
int n, m;
int a[N];//存储坐标插入的值
int s[N];//存储数组a的前缀和
vector alls;  //存储(所有与插入和查询有关的)坐标
vector> add, query; //存储插入和询问操作的数据

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

int main() {
 scanf("%d%d", &n, &m);
 for (int i = 1; i <= n; i++) {
     int x, c;
     scanf("%d%d", &x, &c);
     add.push_back({x, c});
     alls.push_back(x);
 }
 for (int i = 1; i <= m; i++) {
     int l , r;
     scanf("%d%d", &l, &r);
     query.push_back({l, r});
     alls.push_back(l);
     alls.push_back(r);
 }
//排序,去重
 sort(alls.begin(), alls.end());
 alls.erase(unique(alls.begin(), alls.end()), alls.end());
 //执行前n次插入操作
 for (auto item : add) {
     int x = find(item.first);
     a[x] += item.second;
 }
 //前缀和
 for (int i = 1; i <= alls.size(); i++) s[i] = s[i-1] + a[i];
 //处理后m次询问操作
 for (auto item : query) {
     int l = find(item.first);
     int r = find(item.second);
     printf("%d\n", s[r] - s[l-1]);
 }

	return 0;

}

image-20230918154413348

image-20230918154434948


文章作者: Z
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Z !
评论
//
  目录