【算法模板】离散化

news/2024/11/18 12:40:48/

目录

一、模板

二、例题

三、代码

 


一、模板

有许多数分布在数轴上,数的取值范围很广,但是这些数的个数相对来说不是很多,要求对数轴上某个区间上的数进行求和等操作,可使用离散化模版,将数值映射到下标。

基本的步骤可以分为:

1、用一个辅助的数组把你要离散的所有数据存下来。

2、排序,排序是为了后面的二分。

3、去重,因为我们要保证相同的元素离散化后数字相同。

4、索引,再用二分把离散化后的数字放回原数组。

vector<int> 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
}

 

二、数据分析

比如,这组数据:

1,23424,242,65466,242,0

排序后得到:

0,1,242,242,23424,65466

然后会去重,得到:

0,1,242,23424,65466

然后离散化的到:

1,3,2,4,2,0

三、例题

模板题 AcWing 802. 区间和
假定有一个无限长的数轴,数轴上每个坐标上的数都是 0。
现在,我们首先进行 n 次操作,每次操作将某一位置 x 上的数加 c。
接下来,进行 m 次询问,每个询问包含两个整数 l 和 r,你需要求出在区间 [l,r] 之间的所有数的和。
输入格式
第一行包含两个整数 n 和 m。
接下来 n 行,每行包含两个整数 x 和 c。
再接下来 m 行,每行包含两个整数 l 和 r。
输出格式
共 m 行,每行输出一个询问中所求的区间内数字和。
数据范围
−109≤x≤109,
1≤n,m≤105,
−109≤l≤r≤109,
−10000≤c≤10000
输入样例:
3 3
1 2
3 6
7 5
1 3
4 6
7 8
输出样例:
8
0
5

  • 将数组a排序并去重(离散化之前必须先进行排序和去重)
  • 如何快速求出a[i]离散化后的值(二分查找)
#include <iostream>
#include <vector>
#include <algorithm>using namespace std;
const int N = 300010; //n次插入和m次查询相关数据量的上界typedef pair<int, int> PII;
vector<PII> add, query; //存储插入和询问操作的数据
vector<int> alls; //存储所有待离散化的值(所有与插入和查询有关的),将待离散化的值映射到alls的下标int a[N], s[N]; // a[N]用来表示离散化后的数组,s[N]用来表示前缀和
int n, m;
//二分求出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;
}int main() {cin >> n >> m;while (n--) {int x, c;cin >> x >> c;add.push_back({x, c});alls.push_back(x);}while (m--) {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.begin(), alls.end()), alls.end()); 去掉重复元素//处理插入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];//处理询问for (auto item : query) {int l = find(item.first), r = find(item.second);cout << s[r] - s[l - 1] << endl;}return 0;
}

四、注意事项

1、去重并不是把数组中的元素删去,而是重复的部分元素在数组末尾,去重之后数组的大小要减一。

2、二分的时候,注意二分的区间范围,一定是离散化后的区间。

3、如果需要多个数组同时离散化,那就把这些数组中的数都用数组存下来。

 

练习题


http://www.ppmy.cn/news/32300.html

相关文章

一年经验年初被裁面试1月有余无果,还遭前阿里面试官狂问八股,人麻了

最近接到一粉丝投稿&#xff1a;年初被裁员&#xff0c;在家躺平了6个月&#xff0c;然后想着学习下再去面试&#xff0c;现在面试了1个月有余&#xff0c;无果&#xff0c;天天打游戏到半夜&#xff0c;根本无法静下心来学习。下面是他这些天面试经常会被问到的一些问题&#…

java面试八股文之------Java并发夺命23问

java面试八股文之------Java并发夺命23问&#x1f468;‍&#x1f393;1.java中线程的真正实现方式&#x1f468;‍&#x1f393;2.java中线程的真正状态&#x1f468;‍&#x1f393;3.如何正确停止线程&#x1f468;‍&#x1f393;4.java中sleep和wait的区别&#x1f468;‍…

MongoDB数据库从入门到精通系列之八:调整oplog大小

MongoDB数据库从入门到精通系列之八:调整oplog大小 一、oplog的概念二、oplog大小三、调整oplog大小详细步骤一、oplog的概念 操作日志oplog包含了主节点执行的每一次写操作。oplog是存在于主节点local数据库中的一个固定集合。从节点通过查询此集合以获取需要复制的操作。每个…

收到太多领英的提醒邮件怎么办?怎么有选择性的接收?

使用邮箱注-册领英&#xff0c;使用一段时间后会发现经常收到领英的提醒邮件&#xff0c;像下面这样的邮件&#xff0c;没什么太大用处&#xff0c;但是却接收的非常频繁&#xff0c;容易造成混乱把其他有需要邮件忽略&#xff0c;而且占位置。 那如何设置不再接收这样的邮件呢…

拼多多24届暑期实习真题

1. 题目描述&#xff1a; 多多开了一家自助餐厅&#xff0c;为了更好地管理库存&#xff0c;多多君每天需要对之前的课流量数据进行分析&#xff0c;并根据客流量的平均数和中位数来制定合理的备货策略。 2. 输入输出描述&#xff1a; 输入描述&#xff1a; 输入共两行&#x…

字符串函数和内存函数

&#x1f355;博客主页&#xff1a;️自信不孤单 &#x1f36c;文章专栏&#xff1a;C语言 &#x1f35a;代码仓库&#xff1a;破浪晓梦 &#x1f36d;欢迎关注&#xff1a;欢迎大家点赞收藏关注 字符串函数和内存函数 文章目录字符串函数和内存函数前言1. 字符串函数介绍1.1 s…

从参数数量视角理解深度学习神经网络算法 DNN, CNN, RNN, LSTM 以python为工具

从参数数量视角理解深度学习神经网络算法 DNN, CNN, RNN, LSTM 以python为工具 文章目录1. 神经网络数据预处理1.1 常规预测情景1.2 文本预测场景2.全连接神经网络 DNN3.卷积神经网络CNN4.循环神经网络 RNN5.长短期记忆神经网络 LSTMʚʕ̯•͡˔•̯᷅ʔɞʚʕ̯•͡˔•̯᷅ʔ…

快速排序【算法解析,代码模板】

快排的思想是基于 分治 思想的一种排序方法&#xff0c;核心思路分为以下几步&#xff1a; ① 确定 左右边界 l 和 r ② 设置x&#xff0c;值可以是q[l] , q[r] 或者q[(l r) / 2] ③ 递归排序左右区间 我们可能并不清楚x到底在待排数组的哪个位置&#xff0c;但是我们基于…