假定有一个无限长的数轴,数轴上每个坐标上的数都是 00。
现在,我们首先进行 n𝑛 次操作,每次操作将某一位置 x𝑥 上的数加 c𝑐。
接下来,进行 m𝑚 次询问,每个询问包含两个整数 l𝑙 和 r𝑟,你需要求出在区间 [l,r][𝑙,𝑟] 之间的所有数的和。
输入格式
第一行包含两个整数 n𝑛 和 m𝑚。
接下来 n𝑛 行,每行包含两个整数 x𝑥 和 c𝑐。
再接下来 m𝑚 行,每行包含两个整数 l𝑙 和 r𝑟。
输出格式
共 m𝑚 行,每行输出一个询问中所求的区间内数字和。
数据范围
−109≤x≤109−109≤𝑥≤109,
1≤n,m≤1051≤𝑛,𝑚≤105,
−109≤l≤r≤109−109≤𝑙≤𝑟≤109,
−10000≤c≤10000−10000≤𝑐≤10000
输入样例:
3 3
1 2
3 6
7 5
1 3
4 6
7 8
输出样例:
8
0
5
代码
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
const int N = 300010; //n次插入和m次查询相关数据量的上界
int n, m;
int a[N];//存储坐标插入的值
int s[N];//存储数组a的前缀和
vector<int> alls; //存储(所有与插入和查询有关的)坐标
vector<pair<int, int>> 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() {
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++) {
int x, c;
scanf("%d%d", &x, &c);
add.push_back({x, c}); //往后面添加队列
alls.push_back(x); //坐标
}
for (int i = 1; i <= m; i++) {
int l , r;
scanf("%d%d", &l, &r);
//全都往后加
query.push_back({l, r});
alls.push_back(l);
alls.push_back(r);
}
//排序,去重
sort(alls.begin(), alls.end()); //对alls进行排序
alls.erase(unique(alls.begin(), alls.end()), alls.end());
//这时候要求的范围由query记录
for (auto item : add) {
int x = find(item.first);
a[x] += item.second; //x通过alls反应在实际数组中的坐标,x坐标虚拟的。
//对a进行赋值
}
//前缀和
for (int i = 1; i <= alls.size(); i++) s[i] = s[i-1] + a[i];
for (auto item : query) {
int l = find(item.first); //item.first是实际的位置通过find找出再a中的虚拟位置
int r = find(item.second);
printf("%d\n", s[r] - s[l-1]);//输出答案
}
return 0;
}
/*
对vector定义的动态数组进行排序 sort(alls.begin(), alls.end());
alls.erase(unique(alls.begin(), alls.end()), alls.end());
分析:unique 函数并不真正删除元素,而是将重复的元素移动到容器的末尾,
并返回一个指向“新”末尾的迭代器。
然后,可以结合 erase 函数删除这些重复元素。
erase作用:按迭代器范围删除元素 vector<int> vec = {1, 2, 3, 4, 5};
vec.erase(vec.begin() + 2, vec.begin() + 4);
// 删除第3到第4个元素,不包括第5个
// vec 现在是 {1, 2, 5}
删除单个元素 vec.erase(vec.begin() + 1);
// 删除第二个元素
// vec 现在是 {1, 5}
for (auto item : add) auto自动判断add的类型用item遍历
*/
/*
对vector定义的动态数组进行排序 sort(alls.begin(), alls.end());
alls.erase(unique(alls.begin(), alls.end()), alls.end());
分析:unique 函数并不真正删除元素,而是将重复的元素移动到容器的末尾,
并返回一个指向“新”末尾的迭代器。
然后,可以结合 erase 函数删除这些重复元素。
erase作用:按迭代器范围删除元素 vector<int> vec = {1, 2, 3, 4, 5};
vec.erase(vec.begin() + 2, vec.begin() + 4);
// 删除第3到第4个元素,不包括第5个
// vec 现在是 {1, 2, 5}
删除单个元素 vec.erase(vec.begin() + 1);
// 删除第二个元素
// vec 现在是 {1, 5}
for (auto item : add) auto自动判断add的类型用item遍历
*/