AcWing 802. 区间和(离散化算法,python)

news2024/11/28 13:34:30

本篇博客详细讲解一下离散化知识点,通过讲解和详细列题带大家掌握离散化。

题目:

原题链接:https://www.acwing.com/problem/content/description/804/

假定有一个无限长的数轴,数轴上每个坐标上的数都是 0。
现在,我们首先进行 n 次操作,每次操作将某一位置 x 上的数加 c。
接下来,进行 m 次询问,每个询问包含两个整数 l 和 r,你需要求出在区间 [l,r] 之间的所有数的和。

输入格式
第一行包含两个整数 n 和 m。
接下来 n 行,每行包含两个整数 x 和 c。
再接下来 m 行,每行包含两个整数 l 和 r。

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

数据范围
− 1 0 9 ≤ x ≤ 1 0 9 -10^9≤x≤10^9 109x109,
1 ≤ n , m ≤ 1 0 5 1≤n,m≤10^5 1n,m105,
− 1 0 9 ≤ l ≤ r ≤ 1 0 9 −10^9≤l≤r≤10^9 109lr109,
− 10000 ≤ c ≤ 10000 −10000≤c≤10000 10000c10000

输入样例:

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

输出样例:

8
0
5

什么是离散化?

   本题猛的一看似乎就是一道前缀和的模板题,但需要注意到这里所谓的“坐标”的范围较大,范围在 − 1 0 9 ≤ x ≤ 1 0 9 -10^9≤x≤10^9 109x109,为了存下被修改的点的数据,如果将它们的坐标作为数组的下标就需要开一个 2 ∗ 1 0 9 2*10^9 2109大小的数组,肯定会爆内存,况且这里的坐标还有负值,不方便进行存储。

   所以要提出一个新的能方便快捷存数据的算法——离散化

   离散化的内存优化思路是只存储那些被用到的点(在这里指的是“被加了值的点”以及“要查询区间的两个端点”),然后利用一些较小的值来代替它们的坐标进行索引,并最终保持它们的相对位置。

   举个例子:对于“被用到的点”只有四个:1、11、886、320001,如果用传统的存储方式要开1~320001个连续的存储空间,但其实没必要,因为会浪费掉了很多没有用到的空间。其实它们的相对位置可以分别用1(1)、2(11)、3(886)、4(320001)来替代,进而只需要开1~4个连续的存储空间并且全部用上;反观此题的数据量,操作次数决定要存点的个数,n、m均小于等于 1 0 5 10^5 105,所以“被用到的点”最多为 n + 2 m = 3 ∗ 1 0 5 n + 2m =3 *10^5 n+2m=3105个 ,也即内存从 2 ∗ 1 0 9 2 * 10^9 2109优化到了 3 ∗ 1 0 5 3 * 10^5 3105,整整少了4个数量级!

   因此,点的存储位置变为连续,但其表示的值却为离散,故而称其被离散化。

如何离散化?(题解)

   为了能够将较大的坐标点及其该坐标点上的数值存储下来,就需要使用两个映射:

  1. total_num(数组):用来存放题目中用到的坐标点,也就是题中的x, l, r,初始值为空数组。total_num数组表示坐标到相对位置的映射:先将题目中输入样例给出的坐标点全都放入(append)total_num数组后,进行一遍排序和去重,这样就必能保证小的坐标位置在前,大坐标在后,此时下标就是它们新的“相对位置”。
  2. a(数组):用来存放离散化后的坐标的值的变化,初始范围为 3 ∗ 1 0 5 + 10 3 * 10^5 + 10 3105+10 (n + 2m 最大为 3 ∗ 1 0 5 3 * 10^5 3105)。表示相对位置到坐标点上的数值的映射:拿到坐标点的相对位置new_x后,a[new_x] += c就存下了坐标点的数据了。

   这里还需要定义add_num数组用来存放整数(x, c),定义query_num数组,用来存放询问的区间(l, r)

   再定义a的前缀和数组s,预处理完后利用s[r] - s[l - 1]就能得到 [l,r] 区间和了。

   下面来详细讲解一下各数组的作用和具体实现方法:

   首先初始化各个数组,其中a数组和s数组的长度为 3 ∗ 1 0 5 + 10 3 * 10^5 + 10 3105+10,值为0,其余数组初始为空。

   total_num数组为何除了要存被改动点的坐标x还要存储查询区间的两端点l和r呢?

   主要是因为后续要通过s[r] - s[l - 1]来获取到区间和,而必须将它们在坐标轴上的情况也存下来才能知道这个区间的情况,因而它也算作“被用到的点”。

   那么被改动点(x, c)和查询端点(l, r)分别还要再放到add_num和query_num里方便处理。

   具体的存储情况还可以下图为例:
在这里插入图片描述
   这里还有一个难点就是如何进行离散化?也就是如何把total_num数组映射到a数组上?这里需要借用二分来进行插入操作,二分的初始左端点 l 为0,右端点 r 为total_num数组的长度减一,mid = (l+r) // 2,传入参数是x(这里的x是toal_num里的数值,需要对total_num进行遍历并挨个把total_num中的值映射到a数组中),只要total_num[mid] <= x,那么r = mid 否则 l = mid + 1,最后返回值是 l + 1

   为什么返回的是 l + 1 呢?因为a数组和s数组的下标是从1开始的(下标从1开始是方便处理前缀和),所以这里需要进行+1操作。

   下面给出详细代码和注释:

# 读取输入的n和m,分别表示添加操作的数量和查询操作的数量  
n, m = map(int, input().split())  
N = 300010  
a = [0] * N  
s = [0] * N  
# 用于存储添加操作的列表,每个元素是一个元组,包含要添加的数值x和对应的增量c  
add_num = []  
# 用于存储查询操作的列表,每个元素是一个元组,包含查询的区间左端点l和右端点r  
query_num = []  
# 用于存储所有出现过的坐标
total_num = []  
  
# 读取n个添加操作  
for i in range(n):  
    x, c = map(int, input().split())  
    add_num.append((x, c))  
    total_num.append(x)  # 将x添加到total_num中  
  
# 读取m个查询操作  
for i in range(m):  
    l, r = map(int, input().split())  
    query_num.append((l, r))  
    total_num.append(l)  # 将l添加到total_num中  
    total_num.append(r)  # 将r添加到total_num中  
  
# 对total_num进行排序并去重,得到所有唯一出现过的数值  
total_num = list(set(sorted(total_num)))  
  
# 定义一个查找函数,用于在total_num中找到数值x映射到a的位置(索引从1开始)  
def find(x):  
    l = 0  
    r = len(total_num) - 1  
    while l < r:  
        mid = (l + r) // 2  
        if total_num[mid] >= x:  
            r = mid  
        else:  
            l = mid + 1  
    return l + 1
  
# 对每个添加操作进行处理,将增量c添加到对应的位置  
for x, c in add_num:  
    new_x = find(x)  # 找到total_num中x映射到a的位置
    a[new_x] += c    # 将增量c添加到a数组的对应位置  
  
# 计算前缀和数组s  
for i in range(1, N):  
    s[i] = s[i - 1] + a[i]  # 前缀和公式
  
# 对每个查询操作进行处理,计算并输出区间和  
for l, r in query_num:  
    xl = find(l)  
    xr = find(r)  
    print(s[xr] - s[xl - 1])

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

平时使用的正则总结

1、将某一个字符串的后缀名后面加上“!400_500” 使用场景是将minio拿过来的图片压缩尺寸从而压缩其大小&#xff0c;加快渲染的速度。需要在图片的后缀名后面加上尺寸如下&#xff1a; const str //storage-test.test.shiqiao.com/gateway/common/isopen/2024/10/09/e708e9…

科创集团所属园区入驻企业北京铭镓半导体获 “硬科技”潜在独角兽企业认定

近日&#xff0c;科创集团所属工宇园区企业北京铭镓半导体荣获北京市科委、中关村管委会“硬科技”潜在独角兽企业认定。独角兽企业特指具备显著创新力、展现出强劲成长潜力以及获得市场高度认可的企业&#xff0c;是新经济领域发展的标志性存在。 北京铭镓半导体有限公司于202…

如何搭建直播美颜平台?视频美颜SDK的核心技术详解

时下&#xff0c;美颜效果作为提升直播吸引力的重要手段&#xff0c;已经成为主播和观众的共同期待。本篇文章&#xff0c;小编将与大家分享搭建一个高效的直播美颜平台的流程&#xff0c;重点介绍视频美颜SDK的核心技术。 一、直播美颜平台的构建 搭建一个直播美颜平台&#…

vue3:自定义描点定位组件(锚点定位和监听滚动切换)以及遇到的问题

目录 第一章 实现效果 第二章 锚点组件分析 2.1 功能分析 2.2 核心点 第三章 源代码 3.1 数据格式 3.2 代码分析 3.2.1 tab栏以及内容页面 3.2.2 逻辑 第四章 遇到的问题 第一章 实现效果 第二章 锚点组件分析 2.1 功能分析 tab栏以及切换涉及逻辑点击tab切换同时页…

uni-app 打包成app时 限制web-view大小

今天对接一个uni-app的app 内置对方h5 web-view的形式 需要对方在web-view顶部加点东西 对方打的app的web-view始终是全屏的状态&#xff0c;对方表示做不到我要的效果 emmmmmm。。。。。。 于是乎 自己搭了个demo 本地h5跑起来审查了下代码&#xff0c;发现web-view是给绝对定…

关于 CAM350打开钻孔文件时提示出错处理

自动导入CAM350出错时&#xff0c;需要单独导入通孔文件或者槽孔文件查看 第一步&#xff1a; 第二步&#xff1a; 下图中的几处值要与出Allegro中导出文件时的设置一致。 这样应该就能正常查看钻孔文件。

WPF中的Window类

控件分类 在第一篇文章.Net Core和WPF介绍中的WPF的功能和特性部分根据功能性介绍了WPF的控件 名称。 在接下来的文章中&#xff0c;将会详细的介绍各个控件的概念及使用。 主要包括&#xff1a; 内容控件&#xff1a;Label、Button、CheckBox、ToggleButton、RadioButton、…

【长文梳理Webserver核心】框架篇

感谢前人的总结&#xff0c;让一个小白快速成长&#xff0c;那我也贡献一份自己的力量~ 大框架梳理从main函数开始学习 大框架梳理 先摆图&#xff1a; 目光先放到最上面的两个小框架&#xff0c;半同步/半反应堆线程池和异步日志系统&#xff0c;日志系统晓得伐&#xff1f;…

jvm垃圾收集器简介

串行垃圾收集器 串行垃圾收集器&#xff0c;是指使用单线程进行垃圾回收&#xff0c;垃圾回收时&#xff0c;只有一个线程在工作&#xff0c;Java应用中的所有线程都要暂停&#xff0c;等待垃圾回收的完成。这种现象称之为STW(Stop-The-World)&#xff0c;一般的javaweb应用中…

深入理解 pnpm(Performant NPM) 的实现原理及其与 npm 的区别

深入理解 pnpm 的实现原理及其与 npm 的区别 在 JavaScript 生态系统中&#xff0c;包管理器是开发者日常工作中不可或缺的工具。npm&#xff08;Node Package Manager&#xff09;作为 Node.js 的默认包管理器&#xff0c;已经广泛应用于各种项目中。然而&#xff0c;随着项目…

略谈发展测量方法论-高敏雪老师的文章解读与收获

历史地看&#xff0c; GDP 被誉为“世纪性发明”&#xff0c;我们曾经将其视为衡量一国经济发展的重要工具&#xff1b;现实地看&#xff0c;“超越 GDP”是当前出现的带有国际性的口号&#xff0c;内在地包含着对 GDP作为发展指标的批评和替代。 如何看到发展&#xff1f; 如…

apisix云原生网关

定义 企业级网关通过域名、路由将请求分发到对应的应用上&#xff0c;通常承载数千个服务的流量&#xff0c;对稳定性有较高要求。 CNCF全景图 选型 Kubernetes抽象出两个核心概念&#xff1a;Service&#xff0c;为多个Pod提供统一的访问入口&#xff1b;Ingress&#xff…

【STM32-HAL库】实现微秒、毫秒、纳秒延时。(STM32F4系列)(附带工程下载链接)

使用了本代码后不能使用HAL库自带的HAL_Delay函数 使用了本代码后不能使用HAL库自带的HAL_Delay函数 使用了本代码后不能使用HAL库自带的HAL_Delay函数 一、新建工程 可以参考我的新建工程系列教程 stm32-HAL库cubeMX新建工程教程&#xff08;以F103C8T6为例&#xff09;ht…

【长文梳理webserver核心】核心类篇

前言 有三个核心组件支撑一个reactor实现 [持续] 的 [监听] 一组fd&#xff0c;并根据每个fd上发生的事件 [调用] 相应的处理函数。这三个组件就是 EventLoop 、Channel 以及 Poller 三个类&#xff0c;其中 EventLoop 可以看作是对业务线程的封装&#xff0c;而 Channel 可以看…

从零开始搭建一个node.js后端服务项目

一、下载node.js及配置环境 网上很多安装教程&#xff0c;此处就不再赘述了 版本信息 C:\Users\XXX>node -v v20.15.0C:\Users\XXX>npm -v 10.7.0 二、搭建node.js项目及安装express框架 在任意位置创建一个项目文件夹&#xff0c;此处项目文件夹名为test&#xff0…

右键菜单添加cmd

regedit 计算机\HKEY_CLASSES_ROOT\Directory\Background\shell\命令提示符\command 数据&#xff1a;cmd.exe /s /k title 命令提示符 或软件商店安装 Windows Terminal

基于element-ui的upload组件与阿里云oss对象存储的文件上传(采用服务端签名后直传的方式)

服务端签名后直传图解 步骤 1 开通阿里云OSS对象存储服务&#xff0c;创建新的Bucket 2 创建子账户获取密钥 创建用户 添加权限 后端 1 新建一个第三方服务的模块 third-party pom文件 <?xml version"1.0" encoding"UTF-8"?> <project x…

HAL+M4学习记录_3

一、HAL库开发框架 记录HAL学习过程 1.1 CMSIS CMSIS&#xff08;Cortex微控制器软件接口标准&#xff09;&#xff0c;用于提供用户和硬件间的接口&#xff0c;用户通过CMSIS标准对Cortex微控制器内部寄存器单元进行读写 1.2 HAL库 HAL&#xff08;硬件抽象层&#xff09;为…

加固与脱壳04 - 一些简单的脱壳方法

这里只讨论一些简单壳的脱壳方法及其原因。 FRIDA-DEXDump https://github.com/hluwa/FRIDA-DEXDump 适用于不需要研究那些被强保护起来的代码&#xff0c;只是想单纯的看看某个地方的业务逻辑。 原理&#xff1a; 对于完整的 dex&#xff0c;采用暴力搜索 dex035&#xf…

云栖实录 | Hologres3.0全新升级:一体化实时湖仓平台

本文根据2024云栖大会实录整理而成&#xff0c;演讲信息如下&#xff1a; 演讲人&#xff1a; 姜伟华 | 阿里云智能集团资深技术专家、Hologres 负责人 丁 烨 | 阿里云智能集团产品专家、Hologres 产品负责人 活动&#xff1a; 2024 云栖大会 - 商用大数据计算与分析平台论…