思路:本题如果x和l,r的只取范围远小于10e9的话可以采用前缀和直接得出结果,但由于他们的取值范围实在太广了所以无法直接使用前缀和做法,但突破口在于n,m的取值比较小10e5,也就是说虽然下标的大小非常之大但数据实则是非常离散的这时候就用到离散化的写法将原先输入的x中所有出现的下标全部存放在一个新的vector之中最多出现10e5个下标(不重复的情况下)同理l与r也是至多各出现1e5次那么在不重复的情况下最多出现3e5次不一样的下标将其存放在同一个vector然后进行sort与erase得到不重复且有序的一个新的关于x,l,r中都出现过的数字组合而成的数组。最后先进行遍历将x+c也就是用到了pair的连锁使用使得每个x有相对应的c可以相加,但同时还需要添加一个find函数去查找存在于alls中的x的下标,为什么要查找呢?因为此时还不知道这个x在alls中对应什么位置,所以使用二分去查找x在alls中的下标。加完之后使用前缀和得到每个s[i]的大小(因为此时的数组至多至多只有3e5完全可以使用前缀和不用担心太大的时间复杂度)最后一步同理使用find函数找到l,r在alls中的位置最后使用前缀和通过s[r]-s[l-1]得到l到r之间的数字之和,
注:a[]数组之中没有出现过的下标仍然为0,不影响题目的解决。
代码:
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
const int N=300010;
int a[N],s[N];
typedef pair<int,int>PII;
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(){
int n,m;
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(l);
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);
int r=find(item.second);
cout<<s[r]-s[l-1]<<endl;
}
return 0;
}