当前位置: 首页 > news >正文

离散化(保序)

        概念:

        给定一系列要为坐标的值,可能很大,1 到 10e9  ,总不能开一个10e9的数组吧,就要涉及到离散化,将10e5个数(大小在10e9之内)映射到1~10e5,这个映射的过程就叫离散化。

        可能出现的问题:

        1.有重复元素,需要去重。

        2.如何算出a[ i ] 离散后的值。

        离散化模板:(来自y总 https://www.acwing.com/blog/content/277/)

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,从0开始映射
}

 例题:

活动 - AcWing

区间和

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

输入格式

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

输出格式

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

数据范围

−10e9 ≤ x ≤ 10e9,
1≤n,m≤10e5,
−10e9 ≤ l ≤ r ≤ 10e9,
−10000 ≤ c ≤ 10000

输入样例:

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

输出样例:

8
0
5

思路:

        下标范围很大,但我们只用到n+m个(3*10e5);

        由前缀和思想,我们可以很快求出某一区间的值,要用前缀和,那么离散化后的数组下标要从1开始。所以二分返回结果要加1.

        要在某一个下标加上c的话,就算出它离散后的下标,并在那个位置加c;

        比如要求L,R之间的数,我们算出离散化的坐标LK,RK后,求LK,RK之间的和就可以了。

AC代码:

 

#include <bits/stdc++.h>
#include <algorithm>
using namespace std;

const int N = 300010;
int n, m;
int a[N];//要存的数
int s[N];//前缀和

vector<int> alls;//存所有要离散化的值
typedef pair<int, int> PII;
vector<PII> 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() {
	//将所有数读进来,所有用到的下标离散化
	cin >> n >> m;
	for (int i = 0; i < n; i++) {
		int x, c;
		cin >> x >> c;
		add.push_back({ x, c });

		alls.push_back(x);
	}
	for (int i = 0; i < m; i++) {
		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;

}

相关文章:

  • 文本纠错易语言代码
  • 【python】遇上COS美图怎么办?当然是大胆冲呀~
  • 苏小妍java开发工程师-一面面经
  • 「SpringCloud Alibaba」Sentinel实现熔断与限流
  • 赶紧进来看看---详细介绍五种常用字符串库函数 以及对库函数的模拟实现
  • 浅谈 python在密码学的应用
  • lammps数据后处理:python绘制应力应变曲线 附程序代码
  • 机器学习模型2——决策树
  • Java.lang.Character类中codePointAt(CharSequence seq, int index)方法具有什么功能呢?
  • docker-compose 安装Harbor
  • 微服务项目:尚融宝(52)(核心业务流程:充值服务(3))
  • python的小作业
  • 2022届计算机毕业论文(设计)学生选题参考合集推荐收藏
  • AI艺术的背后:详解文本生成图像模型【基于GAN】
  • NR 物理层编码 - slide4 循环码Cyclic Code
  • 345-反转字符串中的元音字母
  • C# 免费离线人脸识别 2.0 Demo
  • go语言学习初探(一)
  • GraphQL学习过程应该是这样的
  • Java小白进阶笔记(3)-初级面向对象
  • jquery ajax学习笔记
  • JS笔记四:作用域、变量(函数)提升
  • Linux后台研发超实用命令总结
  • MySQL常见的两种存储引擎:MyISAM与InnoDB的爱恨情仇
  • PAT A1092
  • SpringBoot 实战 (三) | 配置文件详解
  • vue.js框架原理浅析
  • vuex 笔记整理
  • 得到一个数组中任意X个元素的所有组合 即C(n,m)
  • 翻译 | 老司机带你秒懂内存管理 - 第一部(共三部)
  • 蓝海存储开关机注意事项总结
  • 利用阿里云 OSS 搭建私有 Docker 仓库
  • 人脸识别最新开发经验demo
  • 深度解析利用ES6进行Promise封装总结
  • 跳前端坑前,先看看这个!!
  • 线性表及其算法(java实现)
  • 源码安装memcached和php memcache扩展
  • 进程与线程(三)——进程/线程间通信
  • #pragma once与条件编译
  • #每日一题合集#牛客JZ23-JZ33
  • #数学建模# 线性规划问题的Matlab求解
  • $.type 怎么精确判断对象类型的 --(源码学习2)
  • ${factoryList }后面有空格不影响
  • (2022 CVPR) Unbiased Teacher v2
  • (done) NLP “bag-of-words“ 方法 (带有二元分类和多元分类两个例子)词袋模型、BoW
  • (附源码)springboot人体健康检测微信小程序 毕业设计 012142
  • (算法设计与分析)第一章算法概述-习题
  • (学习日记)2024.04.10:UCOSIII第三十八节:事件实验
  • (循环依赖问题)学习spring的第九天
  • (转)Google的Objective-C编码规范
  • .dwp和.webpart的区别
  • .NET / MSBuild 扩展编译时什么时候用 BeforeTargets / AfterTargets 什么时候用 DependsOnTargets?
  • .Net 8.0 新的变化
  • .net core开源商城系统源码,支持可视化布局小程序
  • .NET Framework与.NET Framework SDK有什么不同?