离散化的本质,是映射,将间隔很大的点,映射到相邻的数组元素中。减少对空间的需求,也减少计算量。
其实映射最大的难点是前后的映射关系,如何能够将不连续的点映射到连续的数组的下标。此处的解决办法就是开辟额外的数组存放原来的数组下标,或者说下标标志,本文是原来上的数轴上的非连续点的横坐标。
此处的做法是是对原来的数轴下标进行排序,再去重,为什么要去重呢,因为本题提前考虑了前缀和的思想,其实很简单,就是我们需要求出的区间内的和的两端断点不一定有元素,提前加如需要求前缀和的两个端点,有利于我们进行二分搜索,其实二分搜索里面我们一般假定有解的,如果没解的话需要特判,所以提前加入了这些元素,从而导致可能出现重复元素。
先来康康原理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;
}