离散化笔记

文章目录

  • 离散化的适用条件
  • 离散化的意思
  • AcWing 802. 区间和
    • CODE
    • CODE2



离散化的适用条件

  • 离散化用于区间求和问题
  • 对于数域极大,而数的量很少的情况下

离散化的意思

  • 背景:对于一个极大数域上的零星几个数进行操作后,求某段区间内的和
    • 其实意思就是大数域映射到一个小数域内。比如我的操作是:第 30 30 30 位加 10 10 10,第 2000 2000 2000 位加 50 50 50,第 1 0 6 10^6 106 位加 100 100 100,映射后我的操作就是a[1] += 10a[2] += 50a[3] += 100,也就是说,我们将零散的数域变得紧凑。

    • 我们如何做到将序列号变紧密而且不重复呢?

      • 首先,我们将需要转化的序列号存在一个数组a[]内,序列号就是我们在大数域内进行操作时的序列号(操作包括对某一号元素进行改值,或者是求区间之和的时候区间的左右端点。这些都是大数域上的序列号)
      • 之后,我们将这些序列号进行排序,然后去掉重复的号。
        • 这步操作的意思是,每个大数域上的序列号在小数域上只能有一个编号与其对应,所以需要去除重复的大序列号
      • 我们用数组a[]的下标作为小数域上与大数域相对应的编号
      • 所以说我们其实是通过一个数组来将序列号缩小的
    • 最后我们使用前缀和算法快速求得多个询问的区间和即可


AcWing 802. 区间和

题目链接:AcWing 802. 区间和

区间和

CODE

#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>using namespace std;typedef pair<int, int> pii; 	 // 定义一个pair类型的别名PII,用于存储一对整数int n, m; 	 // n和 m 分别表示插入操作和查询操作的数量
const int N = 300010; 	// 定义一个常量N,作为数组的大小
int a[N], s[N]; 	 	// a数组用于存储每个位置的数值,s数组用于存储前缀和vector<int> alls; 	 		// alls向量用于存储所有出现过的数
vector<pii> add, query;		// add向量用于存储所有的插入操作,query向量用于存储所有的查询操作int l, r;  	// l和r用于存储查询操作的左右边界
int x, c;  	// x和c用于存储插入操作的数和次数int find(int x) 	 // find函数用于在alls向量中找到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 -- ){cin >> x >> c;add.push_back({x, c});alls.push_back(x); 	 // 将x加入到alls向量中}while (m -- ){cin >> l >> r;query.push_back({l, r});alls.push_back(l);  	// 将l和r加入到alls向量中alls.push_back(r);}// 去重sort(alls.begin(), alls.end());  	// 对alls向量进行排序alls.erase(unique(alls.begin(), alls.end()), alls.end());  // 删除alls向量中的重复元素// 找加入元素的位置并初始化加入数组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){l = find(item.first), r = find(item.second);printf("%d\n", s[r] - s[l - 1]);}
}
  • 其实由上述过程和代码我们可以发现,我们用数组来缩小数域的思路与哈希表不谋而合,所以说我们可以用哈希表来存我们的操作数的序列号,这样的话能将二分的 O ( l o g n ) O(logn) O(logn) 优化到哈希表的 O ( 1 ) O(1) O(1)

  • 但是我们不能用手写的简易哈希表(单指开放寻址和拉链法,能优化成map当我没说)
    因为开放寻址法中,我们需要对对所有数进行取模操作,而模量N是较小的,而数据的编号很大,所以就可能出现我们映射的范围出现问题,例如一个区间[l, r],我们用的模量N满足: l < N < r l < N < r l<N<r,这个时候我们有个尴尬的问题,我们的l映射之后比r大,那么再对这个区间求和时就回出现错误

  • 这个时候就需要我们伟大的 S T L STL STL 出场了,unordered_map很好的解决了我们的问题
    map的实现

    map
    不得不说,C++真的很牛逼啊,那老头真吊

CODE2

#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>using namespace std;typedef pair<int, int> pii;int n, m;
const int N = 300010;
int a[N], s[N];
vector<int> alls;
vector<pii> add, query;
int l, r;
int x, c;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()
{cin >> n >> m;while (n -- ){cin >> x >> c;add.push_back({x, c});alls.push_back(x);}while (m -- ){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());unordered_map<int, int> indx;for(int i = 1; i <= alls.size(); ++i) indx[alls[i - 1]] = i;// 找加入元素的位置并初始化加入数组for(auto item : add){int x = indx[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){l = indx[item.first], r = indx[item.second];printf("%d\n", s[r] - s[l - 1]);}
}

这个代码是我从评论区抄的,位置:https://www.acwing.com/solution/content/13511/,往下翻评论区有个哈希表代码

但是我怎么都看不懂他哈希表的赋值操作

for(int i = 1; i <= alls.size(); ++i) indx[alls[i - 1]] = i;

艹!!!!!!!!!为什么!!!!!!!!!
问bing,他跟我说因为是我在之前对alls[]数组排序去重了,所以区间[l, r]肯定不会映射出错,r映射完肯定比l大,但是我问他是因为键有序所以导致哈希表映射后相对顺序不变吗,它又说不是,然后就是一堆我看不懂的谜语,一直复读复读复读,啊啊啊啊啊啊啊好痛苦啊啊啊啊啊啊

我把对键的赋值改了,不赋为i,但是又 W A WA WA,真的很烦啊,想不出来为什么,等我以后深入一下 S T L STL STL 再说吧 <_>,蒟蒻是这样的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/230969.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

从零搭建AlibabaCloud微服务项目

1&#xff0c;创建maven项目工程如下 equipment-admin 后台equipment-applet 前台或小程序端或app、h5equipment-common 公共模块equipment-gateway 网关equipment-mapper mapper层操作数据库equipment-model 实体类对应数据库表 2&#xff0c;在父pom文件引入依赖 <proper…

Linux常用命令----touch命令

文章目录 Linux操作系统中&#xff0c;touch 命令是一个常用且强大的工具&#xff0c;主要用于创建空文件或设置文件的时间戳。本文将详细介绍 touch 命令的各种参数及其用法&#xff0c;并通过实例演示来加深理解。 1. touch命令基础 touch 命令的基本语法格式为&#xff1a…

100套基于Python的毕业设计-Django项目实战(附源码+论文+演示视频)

大家好&#xff01;我是职场程序猿&#xff0c;感谢您阅读本文&#xff0c;欢迎一键三连哦。 &#x1f9e1;今天给大家分享100基于Python和Django的毕业设计&#xff0c;这些项目都经过精心挑选&#xff0c;涵盖了不同的实战主题和用例&#xff0c;可做毕业设计和课程设计参考…

文件基础知识

计算机中的流&#xff1a;在C语言中将通过输入/输出设备&#xff08;键盘、内存、显示器、网络等&#xff09;之间的数据传输抽象表述为“流”。 1、文本流和二进制流 在文本流中输入输出的数据是一系列的字符&#xff0c;可以被修改在二进制流中输入输出数据是一系列字节&am…

ubuntu系统进入休眠后cuda初始化报错

layout: post # 使用的布局&#xff08;不需要改&#xff09; title: torch.cuda.is_available()报错 # 标题 subtitle: ubuntu系统进入休眠后cuda初始化报错 #副标题 date: 2023-11-29 # 时间 author: BY ThreeStones1029 # 作者 header-img: img/about_bg.jpg #这篇文章标题背…

嵌入式设备与PC上位机通信协议设计的几点原则

嵌入式设备在运行中需要设置参数&#xff0c;这个工作经常由PC机来实现&#xff0c;需要为双方通信设计协议&#xff0c;有代表性协议是如下三种&#xff1a; 从上表可以看到&#xff0c;一般嵌入式设备内存和运算性能都有限&#xff0c;因此固定二进制是首选通信协议。 一&am…

基于深度学习的点云三维目标检测方法综述

论文标题&#xff1a;基于深度学习的点云三维目标检测方法综述 作者&#xff1a;郭毅锋&#xff11;&#xff0c;&#xff12;†&#xff0c;吴帝浩&#xff11;&#xff0c;魏青民&#xff11; 发表日期&#xff1a; 2023 1 阅读日期 &#xff1a;2023 11 29 研究背景&…

基于SpringCloud的动漫论坛

基于SpringCloud的动漫论坛《BOKI》 摘要&#xff1a;鉴于现如今的互联网网站的存在形式&#xff0c;网站内部有可能内嵌论坛&#xff0c;因此&#xff0c;该项目中实现一个整体的、可移植性强的插件式论坛&#xff0c;论坛就有可能突破ACG主题的限制&#xff0c;实现论坛与主…

ArkTS-取消标题与自定义标题栏

文章目录 取消标头自定义标题栏导入Resources自定义跳转动画关于底部tabBar导航文本输入(TextInput/TextArea)自定义样式添加事件可以是onChange可以是onSubmit List列表组件设置主轴方向 网格布局服务卡片-获取地理位置页面获取地理位置服务卡片获取地理位置 可以先看看&#…

将原生Spring项目中某些配置文件中的易变内容参数化

&#x1f609;&#x1f609; 学习交流群&#xff1a; ✅✅1&#xff1a;这是孙哥suns给大家的福利&#xff01; ✨✨2&#xff1a;我们免费分享Netty、Dubbo、k8s、Mybatis、Spring...应用和源码级别的视频资料 &#x1f96d;&#x1f96d;3&#xff1a;QQ群&#xff1a;583783…

SpringBoot——Swagger2 接口规范

优质博文&#xff1a;IT-BLOG-CN 如今&#xff0c;REST和微服务已经有了很大的发展势头。但是&#xff0c;REST规范中并没有提供一种规范来编写我们的对外REST接口API文档。每个人都在用自己的方式记录api文档&#xff0c;因此没有一种标准规范能够让我们很容易的理解和使用该…