C++离散化总结【附模板&例题&代码】

离散化的特点:

  1. 数据的值域比较大,个数比较少【一般l和 r较小的话,比如<=10^5,用前缀和】
  2. 把值域里的数映射到连续的自然数序列里
  3. 整个的值域跨度很大,但是值比价稀疏
  4. 这个映射其实就是把数组的值映射到其对应的下标

可能存在的问题 (我们用一个数组来存储值域里的那些数):

  1. a[ ]中可能有重复的元素,需要去重
  2. 如何做到快速映射(也就是如何快速算出x离散化后的值,即x对应的下标)【这部分的算法:二分】

模板的主要内容:

vector<int> alls; //***** 存储所有待离散化的值
sort( alls.begin(),alls.end() ); //将所有的值排序
alls.erase(  unique( alls.begin(),alls.end(),alls.end() )  ); //去掉重复元素

【unique函数的原理:使得只出现一次的数在一个区域,
剩余的有重复的接在第一个end(最后未重复出现的位置的下标)的后面,
再把其与第二个end之间(数组末尾)的值erase】

// 二分求出对应的离散化的值 
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~n,不 +1的话就是 0~n 
}

【应用】例题:区间和
题目
假定有一个无限长的数轴,数轴上每个坐标上的数都是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;
typedef pair<int,int> PII;
const int N = 300010;

int n,m;
int a[N],s[N];

vector<int> alls;
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(1);
		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;
}

猜你喜欢

转载自blog.csdn.net/Luoxiaobaia/article/details/107669868