区间和
假定有一个无限长的数轴,数轴上每个坐标上的数都是0。
现在,我们首先进行 n 次操作,每次操作将某一位置x上的数加c。
接下来,进行 m 次询问,每个询问包含两个整数l和r,你需要求出在区间[l, r]之间的所有数的和。
输入格式
第一行包含两个整数n和m。
接下来 n 行,每行包含两个整数x和c。
再接下里 m 行,每行包含两个整数l和r。
输出格式
共m行,每行输出一个询问中所求的区间内数字和。
数据范围
−
1
0
9
≤
x
≤
1
0
9
−10^9≤x≤10^9
−109≤x≤109
1
≤
n
,
m
≤
1
0
5
1≤n,m≤10^5
1≤n,m≤105
−
1
0
9
≤
l
≤
r
≤
1
0
9
−10^9≤l≤r≤10^9
−109≤l≤r≤109
−
10000
≤
c
≤
10000
−10000≤c≤10000
−10000≤c≤10000
输入样例:
3 3
1 2
3 6
7 5
1 3
4 6
7 8
输出样例:
8
0
5
由于给定 x x x数据范围为 − 1 0 9 ≤ x ≤ 1 0 9 −10^9≤x≤10^9 −109≤x≤109,但是所要操作的 x x x的个数至多为 3 × 1 0 5 3×10^5 3×105(远小于总的点的个数),那么需要将插入和查询所涉及到的点离散化。
代码:
#include <bits/stdc++.h>
using namespace std;
typedef pair<int,int> pii;
//
const int maxn = 3e5+5;//开3e5+5
int n,m;
int value[maxn]; //存放离散化后的点的值
int preSum[maxn]; //前缀和
vector<int> points; //下标为离散化之后的点
vector<pii> ins; //插入操作
vector<pii> query; //查询操作
//
int find(int x) //返回离散化之后的位置 ,利用二分法找
{
//找到 >= x 的第一个值
int res = lower_bound(points.begin(),points.end(),x) - points.begin();
return res+1; //返回序号从1开始
}
int main()
{
scanf("%d%d",&n,&m);
int x,c,l,r;
for(int i=0;i<n;i++) //读取插入操作
{
scanf("%d%d",&x,&c);
ins.push_back({x,c}); //记录操作
points.push_back(x); //记录下标 待离散化使用
}
for(int i=0;i<m;i++) //读取查询操作
{
scanf("%d%d",&l,&r);
query.push_back({l,r});//记录操作
points.push_back(l); //记录下标 待离散化使用
points.push_back(r);
}
//排序
sort(points.begin(),points.end());
//去重
points.erase(unique(points.begin(),points.end()) , points.end());
//处理插入
for(int i=0;i<ins.size();i++)
{
value[ find(ins[i].first) ] += ins[i].second;
}
//预处理前缀和
for(int i=1;i<=points.size();i++) //离散化后的点的个数 (从 1 开始 ,方便处理边界问题)
{
preSum[i] = preSum[i-1] + value[i];
}
//处理Query
for(int i=0;i<query.size();i++)
{
int l = find(query[i].first);
int r = find(query[i].second);
printf("%d\n",preSum[r] - preSum[l-1]);
}
return 0;
}