适用条件
适用于值域比较大 -1e9 <= x <= 1e9
但是个数比较少 n <= 1e5
离散化的作用机理
d[]: 1 3 100 1500
映射 | | | |
0 1 2 3
出现的问题
一/ d[] 中可能有重复元素
二/ 如何算出x 离散化后对应的值是多少
针对以上问题:
1.首先要去重
2.把其转化为有序序列,可用二分法来找
模板
vector<int> alls //储存待离散化的值
sort(alls.begin(),alls.end()) // 排序
alls.erase(unique(alls.begin(),alls.end()),alls.end()) //去重
find(x) 找出x对应的下标
例题
/求区间和 给定一个无限长的数轴,数轴上每个坐标都是0, -1e9 - 1e9 首先进行n 次操作
每次操作将某一个位置x上的数加上 C
接下来进行 M次询问,你需要求出区间[l,r]之间的所有数之和;/
/*
输入格式
第一行 包含 n m 两个整数
接下来 n行 每行包含两个整数 x 和 c
在接下来m行 每行包含两个整数 l 和 r
输出格式
共m行 每行输出一个询问中所求的区间内的数字和
数据范围
-1e9 <= x <= 1e9
1 <= n,m <=1e5
-1e9 <= l,r <= 1e9
-10000 <= c <= 10000
*/
#include <bits/stdc++.h>
using namespace std;
const int N = 3e5 + 10;
typedef pair<int, int> PII;
int n, m, x, c, l, r;
vector<PII> add, getlr;
vector<int> alls;
int a[N], s[N];
int find(int x)
{
int l = 0, r = alls.size() - 1;
while (l < r)
{
int mid = l + r + 1>> 1;
if (alls[mid] <= x) l = mid;
else r = mid - 1;
}
return r + 1; //因为是前缀和,所以下标要从1开始
}
int main()
{
cin >> n >> m;
while (n --)
{
cin >> x >> c;
add.push_back({x, c});
alls.push_back(x);
}
for(int i = 0; i < m; i ++)
{
cin >> l >> r;
getlr.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 (auto seg : add)
{
int idx = find(seg.first);
a[idx] += seg.second;
}
for (int i = 1; i <= alls.size(); i ++) s[i] = s[i - 1] + a[i];
for (auto seg : getlr)
{
l = find(seg.first);
r = find(seg.second);
cout << s[r] - s[l - 1] << endl;
}
system("pause");
return 0;
}