题目描述
输出样例
3 3
1 2
3 6
7 5
1 3
4 6
7 8
输出样例
8
0
5
思路
离散化 + 前缀和
为什么用前缀和?
求解问题为给定区间的和,且求解的整个区间已经是固定的(对数轴上每个点的操作在之前已经全部完成),这样我们只进行一次前缀和,之后便可以在O(1)的时间复杂度内访问给定区间内的和。
为什么用离散化?
题目给定的数轴上的数据范围为-1e9~1e9,跨度为2e9,如果用数组数轴上的每个点都存储下来,需要开2e9的数组,肯定会爆内存。但是,我们可以看到,访问的区间最多有105,因此我们可以将-1e9至1e9映射到0至105,这样数组就可以放的下了
如何进行离散化,即如何进行映射?
首先我们需要对操作的所有区间端点进行排序和去重,去重的目的是了使每一个端点都对应唯一的映射值,排序是为了让区间端点映射后的值不改变相对位置
接着,我们借助二分,使每个值找到其对应的映射值,二分的范围就是不同的区间端点数
AC代码
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
typedef pair<int,int> PII;
const int N=1000010;
vector<PII> add;//每次操作将某一位置x上的数加c
vector<int> pos;//出现的点
vector<PII> p;//待访问的点
int a[N];//前缀和数组
int find(int x)
{
int l = 0,r = pos.size() - 1;
while(l < r)
{
int mid = l + r >> 1;
if(pos[mid] < x)
l = mid + 1;
else
r = mid;
}
return l + 1; //为了与前缀和下标保持一致,我们将下标映射到1~pos.size() - 1
}
int main()
{
int n, m;
cin >> n >> m;
int x, c;
for(int i = 0; i < n; i ++)
{
cin >> x >> c;
add.push_back({x, c});
pos.push_back(x);
}
for(int i = 0; i < m;i ++)
{
int l, r;
cin >> l >> r;
pos.push_back(l);
pos.push_back(r);
p.push_back({l, r});
}
sort(pos.begin(),pos.end());
pos.erase(unique(pos.begin(),pos.end()),pos.end());
for(int i = 0; i < add.size(); i++)
{
int b = find(add[i].first);
a[b] += add[i].second;
}
for(int i = 1; i <= pos.size(); i ++) //前缀和操作
a[i] += a[i-1];
for(int i = 0;i < p.size(); i ++)
{
int b = find(p[i].first);
int c = find(p[i].second);
cout << a[c] - a[b - 1] << endl;
}
return 0;
}
欢迎大家批评指正!!!