离散化 = =

理解:

模板:

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。

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

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

输入格式

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

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

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

输出格式

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

数据范围

−10^9≤x≤10^9,
1≤n,m≤10^5,
−10^9≤l≤r≤10^9,
−10000≤c≤10000

输入样例:

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

输出样例:

8
0
5

AC代码:

#include<bits/stdc++.h>

using namespace std;

const int N = 3e5 + 10;

typedef pair<int, int> PII;
 
int a[N];
int s[N]; // 前缀和 

vector<int> alls;  // 存储所有待离散化的值
vector<PII> add, query; 


//二分求出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开始比较好做,不用处理边界) 
} 

int main()
{
    int n,m;
	
	cin >> n >> m; 
	
	for(int i = 0 ; i < n ; i ++) // n次操作:数轴上的x位置加上c 
	{
		int x,c;
		cin >> x >> c;
		add.push_back({x,c}); // 添加每一对x,c
		
		alls.push_back(x); // x放入待离散化的数组里面去 
	}
	
	for(int i = 0 ; i < m ; i ++) // 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) // 相当于把add全部遍历一遍 
	{
		int x = find(item.first); // x是离散化之后的值即坐标 
		a[x] += item.second; // 在离散化之后的位置上加上我们要加的数c 
	} 
	
	//预处理前缀和
	for(int i = 1 ; i <= alls.size() ; i ++) s[i] = s[i - 1] + a[i];
	
	//处理询问
	for(auto item : query) // 范围for循环用于遍历容器内所有元素 
	{
		int l = find(item.first) , r = find(item.second); // item.first存的是区间左端点的值,l存的是左端点离散化后的值,右端点同理
		 
		cout << s[r] - s[l - 1] << endl;
	} 
	
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

21RGHLY

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值