假定有一个无限长的数轴,数轴上每个坐标上的数都是 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
输入样例:
3 3
1 2
3 6
7 5
1 3
4 6
7 8
输出样例:
8
0
5
方法一:
被难住了..不熟悉C++ STL,故知道离散化和排序但不会去重 23333
分析:
- 数轴是无限长的,所以x∈R,所以不能开个数组并且下标代表x,而输入的x个数是有限的,所以可以将其离散化,比如
1 20 100 12312
映射到数组下标1 2 3 4
- 这题要进行有序的离散化,也就是离散化之后用于映射的数组存储的x是有序的,便于后面使用二分搜索
- 最后利用前缀和进行求区间和操作
做法:
- 将输入数据全部读入,
alls
用来映射 ( 数组下标, x ),即先把所有x读入alls,再用STL函数排序和去重得到正确的映射数据 - 用
nums
存储每个x上对应的c - 最后前缀和,即区间和
补充:
find()
函数返回大于x的最小元素下标(当x大于最大元素,返回最大元素下标)- 核心在于理解离散化
#include <bits/stdc++.h>
using namespace std;
typedef pair<int, int> PII;
int n, m;
int nums[300010];
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() {
scanf("%d%d", &n, &m);
for (int i = 0; i < n; i++) {
int x, c;
scanf("%d%d", &x, &c);
alls.push_back(x);
add.emplace_back(x, c);
}
for (int i = 0; i < m; i++) {
int l, r;
scanf("%d%d", &l, &r);
alls.push_back(l);
alls.push_back(r);
query.emplace_back(l, r);
}
// 排序+去重
sort(alls.begin(), alls.end());
alls.erase(unique(alls.begin(), alls.end()), alls.end());
// 处理插入
for (auto item: add) {
int x = find(item.first);
nums[x] += item.second;
}
// 前缀和
for (int i = 1; i <= alls.size(); i++) nums[i] += nums[i-1];
for (int i = 0; i < m; i++) {
int l = find(query[i].first);
int r = find(query[i].second);
printf("%d\n", nums[r] - nums[l-1]);
}
}