首先给你一个序列,我们有一些数值,这些数值的范围比较大,值域可能是 [ 0 , 1 0 9 ] [0,10^9] [0,109],但是里面的个数是很少的,个数可能是 [ 0 , 1 0 5 ] [0,10^5] [0,105],有些时候我们需要利用这些值当作数组的下标来做,这是我们是不可能去开一个 1 0 9 10^9 109的数组的,因此,我们就要将这个序列里面的数映射到一个从0开始的连续自然数。
但是在离散化的时候我们应该注意哪一些问题呢?
(1)序列里面的元素有可能是 重 复 \color{red}{重复} 重复的,这就涉及到 去 重 \color{red}{去重} 去重的操作。
(2)如何快速算出 x x x(x表示序列里面的数值)离散化后新的数组的下标值。这里用 二 分 查 询 \color{red}{二分查询} 二分查询来实现。
这里的离散化一定是保须的
1:首先将这个序列里面的数进行从小到大排序。
2:接下来就是去重操作,c++里并没有直接去重的函数,但是我们是可以用函数来实现的,接下来阐述一下去重的原理, u n i q u e unique unique函数是返回排序后里面没有重复元素的最后一个值的下标返回,其实后面有就是重复的数,所以我们通过 e r a s e erase erase函数将后面重复的函数删掉。
c++里面是有专门的 u n i q u e unique unique函数的,但是我们可不可以手动实现一个 u n i q u e unique unique函数ne?当然也是可以的,接下来我就讲讲这个函数的具体实现算法。
(1)将不重复的数全部选出来,满足下面两个条件中的一个条件就行
1:这个数是序列中的第一个数
2:这个数与他前面一个数是不相等的,即 a [ i ] ! = a [ i − 1 ] a[i]!=a[i-1] a[i]!=a[i−1]
(2)实现我们通过双指针的方法
i i i指针表示遍历这个序列里面所有的数, j j j指针表示当前存到的第几个不同的数
(3)注意,这里我们返回的是一个迭代器
vector<int>::iterator unique(vector<int>& a) {
int j = 0;//j表示当前存下的第几个不同的数
for (int i = 0; i < a.size(); i++)
if (!i || a[i] != a[i - 1])
a[j++] = a[i];
return a.begin() + j;
}
3:如何快速算出 x x x离散化后的值呢?具体实现看代码
sort(alls.begin(), alls.end());
alls.erase(unique(alls.begin(), alls.end()), alls.end());
int find(int x) {//需要查询的值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;//返回什么具体情况而定,如果你要求前缀和的话,那么你就要加1,因为前缀和处理的时候我们都是从下标1开始的
}
数轴上面有一些数,然后将他们离散化之后存在数组里面就是 a [ 1 ] = 5 , a [ 2 ] = 3 , a [ 3 ] = 6 , a [ 4 ] = 1 , … … , a [ 8 ] = 7 a[1]=5, a[2]=3, a[3]=6, a[4]=1, …… ,a[8]=7 a[1]=5,a[2]=3,a[3]=6,a[4]=1,……,a[8]=7
离 散 化 的 核 心 就 是 将 需 要 离 散 化 的 值 映 射 到 从 0 开 始 或 者 从 1 开 始 的 连 续 自 然 数 \color{red}{离散化的核心就是将需要离散化的值映射到从0开始或者从1开始的连续自然数} 离散化的核心就是将需要离散化的值映射到从0开始或者从1开始的连续自然数
题意:
假定有一个无限长的数轴,初始时数轴的下标权威0,现在,首先进行n次操作,将位置为x的地方加上c,然后接下来有m次询问,每次询问包含两个整数l,r。我们要求的是 [ l , r ] [l,r] [l,r]区间里面的和
输入格式:
第一行两个数n和m;
接下来n行每行两个数x,c;
最后m次询问每行两个数l,r;
数据范围:
− 1 0 9 -10^9 −109<= x x x<= − 1 0 9 -10^9 −109
1<= n , m n,m n,m<= 1 0 5 10^5 105
− 1 0 9 -10^9 −109<= l l l<= r r r<= − 1 0 9 -10^9 −109
− 10000 -10000 −10000<= c c c<= 10000 10000 10000
#include
#include
#include
using namespace std;
/*
3 3
1 2
3 6
7 5
1 3
4 6
7 8
*/
const int N = 30010;
int a[N], s[N];//x离散化后的数组的下标所对应的c
typedef pair<int, int> PII;
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() {
int n, m;
cin >> n >> m;
for (int i = 0; i < m; i++) {
int x, c;
cin >> x >> c;
add.push_back({ x,c });
alls.push_back(x);
}
for (int i = 0; i < m; i++) {
int l, r;
cin >> l >> r;
query.push_back({ l,r });
alls.push_back(l);
alls.push_back(r);
}
sort(alls.begin(), alls.end());
alls.erase(unique(alls.begin(), alls.end()), alls.end());
for (int i = 0; i < add.size(); i++) {
int x = find(add[i].first);
//cout << x << endl;
a[x] += add[i].second;
}
/*for (int i = 0; i < alls.size(); i++)cout << a[i] << endl;
cout << endl;*/
for (int i = 1; i <= alls.size(); i++)s[i] = s[i - 1] + a[i];
for (int i = 0; i < query.size(); i++) {
int l = find(query[i].first);
int r = find(query[i].second);
cout << s[r] - s[l-1] << endl;
}
return 0;
}