目录
一:概念定义
简单来说,就是把一些非常零散的点重新分配到从1~n的自然数,这个分配过程也可以称作映射,比如坐标轴范围是-10^9~10^9,但是其中有实际数值的坐标只有十个,我们把这个十个数字映射到1~10即可。
我们用一幅图来描述一下,这是个无限宽度的坐标轴:
坐标点的数字没有规律,如果要我们求某一个区间的和,我们容易联想到前缀和,但是这个区间太宽,而且其中有很多坐标的数值是0,没有必要参与前缀和的过程,因此我们需要映射,拿上图举例子:
原本我们求的【-47,96】的区间和就转化为【1,10】的映射区间和,效率大幅提升。
二:题目描述
假定有一个无限长的数轴,数轴上每个坐标上的数都是 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
三:思路解析
首先,输入数据很多是成双出现,因此我们可以用pair结构来存储
整体大方向:去重+映射+前缀和
四:万年无误代码模板
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
typedef pair<int, int> PII;
const int N = 300010;//输入由是十万个坐标,检测l有十万个,r有十万个,因此我们将N开到三十万+10
int n, m;
int a[N], sum[N];
vector<int> all;
vector<PII> add, query;
int find(int x)//find函数用来寻找x在所有输入坐标的排名(映射)
{
int l = 0, r = all.size() - 1;
while (l < r)
{
int mid = l + r >> 1;
if (all[mid] >= x) r = mid;
else l = mid + 1;
}
return r + 1;//r+1是因为映射一般从1开始所以加1,因为前缀和习惯从1开始
}
int main()
{
cin >> n >> m;
for (int i = 0; i < n; i ++ )
{
int x, c;
cin >> x >> c;
add.push_back({x, c});
all.push_back(x);
}
for (int i = 0; i < m; i ++ )
{
int l, r;
cin >> l >> r;
query.push_back({l, r});
all.push_back(l);
all.push_back(r);
}
// 去重
sort(all.begin(), all.end());
all.erase(unique(all.begin(), all.end()), all.end());
// 处理插入
for (auto i : add)
{
int x = find(i.first);
a[x] += i.second; //求出映射从1~n的数值,i.second就是题目中的c
}
// 预处理前缀和
for (int i = 1; i <= all.size(); i ++ ) sum[i] = sum[i - 1] + a[i];
// 简单输出
for (auto i: query)
{
int l = find(i.first), r = find(i.second);
cout << sum[r] - sum[l - 1] << endl;
}
return 0;
}
五:常见问题
1.为什么要去重?
2.为什么要把l和r也加入到all中?
3.去重函数怎么写?
1. 其实不用去重也不影响代码实现,但是去重之后就会很严格的映射1~n,并且是一对一的关系,我们的find函数(其实就是二分查找)是查找x的映射,而且是第一个大于等于x的值,本体中其实最后find返回的就是被查找值x的下标
2.比如要求【4,200】这段区间和,假设其映射是【3,9】,我们需要通过s【9】-s【2】来得出答案,如果不输入l,r,就得不到其映射,就无法通过前缀和来得到答案
3.首先,unique函数是返回第一个重复数字的地址,将不重复的数字放到前面,erase实现重复数字到最后数字的去除工作
六:相关前缀和以及二分的知识链接
创作不易,建议点赞+收藏+关注,以免变成付费资源或者找不到宝贝文章了。
基础集训结束后将开展拔高系列