区间和
假定有一个无限长的数轴,数轴上每个坐标上的数都是 0。
现在,我们首先进行 n 次操作,每次操作将某一位置 x 上的数加 c。
接下来,进行 m 次询问,每个询问包含两个整数 l 和 r,你需要求出在区间 [l,r][�,�] 之间的所有数的和。
输入格式
第一行包含两个整数 n 和 m。
接下来 n 行,每行包含两个整数 x 和 c。
再接下来 m 行,每行包含两个整数 l 和 r。
输出格式
共 m 行,每行输出一个询问中所求的区间内数字和。
数据范围
−10^9≤x≤10^9,
1≤n,m≤10^5,
−10^9≤l≤r≤10^9,
−10000≤c≤10000
输入样例:
1 2 3 4 5 6 7
| 3 3 1 2 3 6 7 5 1 3 4 6 7 8
|
输出样例:
数轴的长度是10的9次方级别,需要进增加和查询的点的数量是10的5次方级别。这些点在数轴上的分布非常稀疏,如果直接使用前缀和会超时。
考虑把这些稀疏的点通过一个映射关系映射到一块连续的区域,操作次数就会变为10的5次方级别,再使用前缀和就可以了。
- 把所有需要进行增加和查询的点记录到
all
数组里,对数组进行排序。
- 用二分找到这个点出现的初始位置,作为映射后的数组下标。
- 在映射后的数组上使用前缀和
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
| #include<iostream> #include<vector> #include<algorithm>
using namespace std; const int N = 300010; vector<int> all; vector<pair<int,int>> add,query; vector<int> a(N),s(N);
int find(int x){ int l=0,r=all.size()-1; while(l<r){ int mid=l+r>>1; if(all[mid]<x) l=mid+1; else r=mid; } return l+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}); all.push_back(x); } for(int i=0;i<m;i++){ int l,r; cin>>l>>r; query.push_back({l,r}); all.push_back(l); all.push_back(r); } sort(all.begin(),all.end()); for(auto i:add){ int x=find(i.first); a[x]+=i.second; } for(int i=1;i<=all.size();i++) s[i]=s[i-1]+a[i-1]; for(auto i:query){ int l=i.first; int r=i.second; cout<<s[find(r+1)]-s[find(l)]<<endl; } return 0; }
|