离散化
保序的离散化,小的元素依旧在前面
能用到的元素个数非常少,例如1e5数量级
但是元素的值域非常大,比如1e9,有些题目要以元素的值作为下标来做
比如,累计某个元素出现的次数,vis[a[i]]++;把值域,这个序列映射到1e5范围内,把a[i]这个值映射到1~1e5这些下标
int find(int x){
//alls数组里装的就是待离散化映射到更小区间段的下标
//x就是一个待离散化的下标
int l=0;
int r=alls.size()-1;
while(l<r){
int mid=(l+r)>>1;
if(x>alls[mid])l=mid+1;
else r=mid;
}
return l+1;//加1是为了从下标1开始映射,或者r+1
}
l+1从下标1开始映射,要用到前缀和时,映射到从1开始的自然数
找到a[i]离散化之后对应的下标位置k,为lsh【k】加上c
加数操作要映射,求区间和的时候也要映射
数据范围比较小,可以用前缀和
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
const int N=3e5+5;
//要用到的下标数量有3e5数量级,add和query操作用到的下标是不同的
typedef pair<int,int> pii;
vector<int> alls;
vector<pii> add;
vector<pii> query;
int a[N];//所有的数通过离散化映射到1~N
int s[N];//a数组前缀和
int find(int x){
//alls数组里装的就是待离散化映射到更小区间段的下标
//x就是一个待离散化的下标
int l=0;
int r=alls.size()-1;
while(l<r){
int mid=(l+r)>>1;
if(x>alls[mid])l=mid+1;
else r=mid;
}
return l+1;
}
int main(){
int n,m;
cin>>n>>m;
int x,c,l,r;
while(n--){
cin>>x>>c;
alls.push_back(x);//把x加入到待离散化的数组当中去
add.push_back({x,c});
}
while(m--){
cin>>l>>r;
alls.push_back(l);
alls.push_back(r);//左右区间的值也要加入到待离散化的数组当中去
query.push_back({l,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 ll=find(item.first);
int rr=find(item.second);
cout<<s[rr]-s[ll-1]<<endl;
}
return 0;
}