题目链接:https://www.acwing.com/problem/content/description/804/
时/空限制:2s / 64MB
题目描述
假定有一个无限长的数轴,数轴上每个坐标上的数都是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
解题思路
题意:首先进行n次操作,将某一位置x上的数加c。然后进行m次询问求出在区间[l, r]之间的所有数的和。
思路:因为存储的下标实在太大了,如果直接开这么大的数组,根本不现实,还有就是数轴,要是采用下标的话,可能存在负值,所以也不能,如果用哈希表的话,我们可能需要从-1e9遍历到1e9,因为哈希表不能排序,所以我们一般不能提前知道哪些数轴上的点存在哪些不存在,所以一般是从负的最小值到正的最大值都枚举一遍,时间复杂度太高,所以就要离散化。
离散化的本质,是映射,将间隔很大的点,映射到相邻的数组元素中。减少对空间的需求,也减少计算量。
所以我们首先可以对坐标进行离散化,然后再根据离散化后的下标来进行前缀和,然后就可以输出区间[l, r]之间的和了。
Accepted Code:
/*
* @Author: lzyws739307453
* @Language: C++
*/
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 100005;
int hash_[MAXN << 2], bits[MAXN << 2];
struct Hash {
int l, r;
}Q[MAXN], p[MAXN];
int main() {
int n, m, cnt = 0;
scanf("%d%d", &n, &m);
for (int i = 0; i < n; i++) {
int x, c;
scanf("%d%d", &p[i].l, &p[i].r);
hash_[cnt++] = p[i].l;
}
for (int i = 0; i < m; i++) {
scanf("%d%d", &Q[i].l, &Q[i].r);
hash_[cnt++] = Q[i].l;
hash_[cnt++] = Q[i].r;
}
sort(hash_, hash_ + cnt);//排序
cnt = unique(hash_, hash_ + cnt) - hash_;//去重
for (int i = 0; i < n; i++) {
int x = lower_bound(hash_, hash_ + cnt, p[i].l) - hash_;//映射
bits[x] += p[i].r;
}
for (int i = 1; i < cnt; i++)
bits[i] += bits[i - 1];
for (int i = 0; i < m; i++) {
int l = lower_bound(hash_, hash_ + cnt, Q[i].l) - hash_;
int r = lower_bound(hash_, hash_ + cnt, Q[i].r) - hash_;
printf("%d\n", bits[r] - bits[l - 1]);
}
return 0;
}