C++算法——离散化

离散化的本质,是映射,将间隔很大的点,映射到相邻的数组元素中。减少对空间的需求,也减少计算量。

其实映射最大的难点是前后的映射关系,如何能够将不连续的点映射到连续的数组的下标。此处的解决办法就是开辟额外的数组存放原来的数组下标,或者说下标标志,本文是原来上的数轴上的非连续点的横坐标。

此处的做法是是对原来的数轴下标进行排序,再去重,为什么要去重呢,因为本题提前考虑了前缀和的思想,其实很简单,就是我们需要求出的区间内的和的两端断点不一定有元素,提前加如需要求前缀和的两个端点,有利于我们进行二分搜索,其实二分搜索里面我们一般假定有解的,如果没解的话需要特判,所以提前加入了这些元素,从而导致可能出现重复元素。

先来康康原理8

在这里插入图片描述

在代码中有着一些方法,如pair和vector<>的用法,可以先去了解,在回过头看代码。pair介绍(转载:https://blog.csdn.net/sevenjoin/article/details/81937695?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522160138442019195188305215%2522%252C%2522scm%2522%253A%252220140713.130102334…%2522%257D&request_id=160138442019195188305215&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allfirst_rank_ecpm_v3~pc_rank_v2-1-81937695.first_rank_ecpm_v3_pc_rank_v2&utm_term=c%2B%2B%E7%9A%84pair&spm=1018.2118.3001.4187)

在这里插入图片描述
在这里插入图片描述

#include<iostream>
#include<vector>
#include<string>
#include<algorithm>

using namespace std;

typedef pair< int , int > PII;

const int N = 300010;

int n , m; //输入n个整数,对m个区间进行求和 

//a[N]下标表示映射后数组的下标,值表示该下标的值
//s[N]表示前缀和 
int a[N] , s[N];

vector<int> alls; //把原数组中每个数的下标以及查询的下标(单凡出现过的下标) 

vector<PII> add , query; //add存储原数组的下标和值,query存储的是要查的左右端点{l,r} 

int find( int x )
{
	int l = 0 , r = alls.size() - 1 ;
	
	//利用二分找到原数组x下标对应的 
	while(l < r)
	{
		int mid = l + r >> 1;
		
		if( alls[mid] >= x ) r = mid;
		else l = mid + 1;
	}
	
	return r + 1;
}

vector<int>::iterator unique(vector<int> &a)
{
    int j = 0;
    for (int i = 0; i < a.size(); i ++ )
        if ( !i || a[i] != a[i - 1] )
            a[j ++ ] = a[i];
    // a[0] ~ a[j - 1] 所有a中不重复的数

    return a.begin() + j;
}


int main()
{
	cin >> n >> m;
	
	//输入n个数到add中 ,其中x表示下表,c表示值
	for(int i = 0 ; i < n ; i++ )  
	{
		int x , c;
		cin >> x >> c;
		add.push_back( {x , c} ); 
		
		alls.push_back(x);
	}
	
	//输入m个数到alls中,其中l表示左端点 , r表示右端点 
	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中的每个数的下标进行排序 
	//利用unique函数除去重复项 
	alls.erase( unique( alls ) , alls.end() );
	 
	 //处理插入
	for( auto item : add ) //遍历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;
}
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值