对数据范围较大,但有用的数据较少的题目使用。
中心思想:把所有用到的元素的位置按照一定的顺序映射到一个从0或1为起点的数组中,并把所有用到的元素的值存储在映射数组中,可以利用二分查找确定某个元素映射的位置。
#include<bits/stdc++.h>
using namespace std;
int arr[300010],pre_sum[300010];//真实有用的坐标最多只有n+2*m个,(n次修改会用n个位置,m次询问会用2*m个位置)
vector<pair<int,int>> add,add2;
vector<int> xiab;
int f(int x){
vector<int>::iterator i=lower_bound(xiab.begin(),xiab.end(),x);
return i-xiab.begin();
}
int main(){
int n,m;
cin>>n>>m;
//先把所有用到的下标放到数组中
for(int i=1;i<=n;i++){
int x,c;
cin>>x>>c;
add.push_back({x,c});
xiab.push_back(x);
}
for(int i=1;i<=m;i++){
int l,r;
cin>>l>>r;
add2.push_back({l,r});
xiab.push_back(l);
xiab.push_back(r);
}
//排序所有用到的下标,然后去重。
sort(xiab.begin(),xiab.end());//排序去重,为什么不用set,因为set类型的迭代器只能进行++或--操作,查询其中元素位置时不便。
xiab.erase(unique(xiab.begin(),xiab.end()),xiab.end());//unique()去重,返回去重后最后一个元素的位置
//开一个数组记录所映射位置的元素值,利用二分查找映射的位置,需要加值的进行处理。
for(int i=1;i<=n;i++){
int t=f(add[i-1].first)+1;
arr[t]=arr[t]+add[i-1].second;
}
for(int i=1;i<=xiab.size();i++){
pre_sum[i]=pre_sum[i-1]+arr[i];
}
for(int i=0;i<m;i++){
int l=f(add2[i].first)+1;
int r=f(add2[i].second)+1;
cout<<pre_sum[r]-pre_sum[l-1]<<endl;
}
return 0;
}