思路
结合注释,流程就是:
1. 先存储while(n--)、while(m--)
中用到的所有数轴点(包括询问区间端点和增值操作点)、操作区间端点{l,r}
和操作值{x,c}
。
2. 然后使用need_idx[]
进行离散化操作。即先进行排序然后去重,结果就是得到的数组need_idx[]
存储的值是从小到大、用到的数轴点,数组索引是数轴点映射之后的下标。
3. 离散化之后根据Find()
函数读取增值操作,然后进行前缀和的初始化,然后处理区间和的询问。注意这一部分都是基于映射之后的下标进行的,缩小了原来稀疏索引的范围。
4. 只需要映射用到的数轴点即可,因为默认值是0,如果没有增值,那么还是0,对最终的前缀和没有影响。
5. 注意前缀和要基于1的索引,所以二分查找返回的索引+1。
#include<iostream>
#include<cstdio>
#include<vector>
#include<utility>
#include<algorithm>
using namespace std;
const int N = 300010;
int val[N];//基于映射下标存储操作值
vector<int> need_idx; //离散化的核心:存储的值是从小到大、用到的数轴点,数组索引就是数轴点映射之后的下标
vector<pair<int,int>> opt,que; //存储增值操作{x,c}和询问区间{l,r}
int n,m;
int Find(int x) //找到某个数轴点映射之后的下标
{
int l = 0, r = need_idx.size()-1;//二分的索引范围?
while(l < r)
{
int mid = l+r >> 1;
if(need_idx[mid] >= x) //need_idx[i]和x都是数轴点,进行比较,二分答案
r = mid;
else
l = mid+1;
}
return l+1; //注意前缀和要求基于1的索引
}
int main()
{
scanf("%d%d", &n,&m);
while(n--)
{
int x,c;
scanf("%d%d", &x,&c);
need_idx.push_back(x); //存储需要用到的数轴点
opt.push_back({x,c}); //存储一组增值操作
}
while(m--)
{
int l,r;
scanf("%d%d", &l,&r);
need_idx.push_back(l); need_idx.push_back(r); //存储用到的数轴点
que.push_back({l,r}); //存储询问区间
}
//先排序,再去重
sort(need_idx.begin(), need_idx.end());
need_idx.erase(unique(need_idx.begin(), need_idx.end()), need_idx.end());
//执行操作
for(auto ele : opt)
{
int idx = Find(ele.first); //映射之后的下标
val[idx] += ele.second;
}
//前缀和初始化
for(int i = 1; i <= N; i ++)
val[i] = val[i-1] + val[i];
for(auto ele : que)
{
int l = Find(ele.first);
int r = Find(ele.second);
printf("%d\n",val[r]-val[l-1]);
}
return 0;
}