
💡Yupureki:个人主页
🌸Yupureki🌸的简介:

目录
[1. 离散化思想](#1. 离散化思想)
[2. 火烧赤壁](#2. 火烧赤壁)
[3. 贴海报](#3. 贴海报)
离散化
1. 离散化思想
当题目中的数值很大,但数据量不是很大,并且我们需要利用数据的值来映射数组的下标时,我们可以采用离散化的思想,使每一个数据缩小成一个很小的值
例如对于[99999,9999999999,99999999999,9999999999999999]的数组中,元素的数值很大,我们不方便用整型或者字符串存储
这个时候我们观察数组,可以将数组进行排序 (例如从小到大),然后把元素在数组中的下标 当作一个新的值放在另一个数组中,这种叫做映射 ,哈希表就是一个典型例子

cpp
#include <iostream>
#include <unordered_map>
#include <algorithm>
using namespace std;
const int N = 1e5 + 10;
int n;
int v[N]; // 原始数据
int tmp[N]; // ⽤来排序的数组
int cnt;
unordered_map<int, int> id; // 记录离散化之后的值
int main()
{
cin >> n;
for (int i = 1; i <= n; i++)
{
int x; cin >> x;
v[i] = x;
tmp[i] = x; // 数据放进离散化数组中
}
// 离散化:排序 + 放进哈希表中
sort(tmp + 1, tmp + 1 + n);
for (int i = 1; i <= n; i++)
{
if (id.count(tmp[i])) continue; // 如果已经存过这个数,不做处理
cnt++; // 这个数映射之后的值
id[tmp[i]] = cnt; // 放进哈希表中
}
// 找到离散化之后的值
for (int i = 1; i <= n; i++)
{
int x = v[i];
cout << x << "离散化之后是: " << id[a[i]] << endl; // ⼆分查找离散化之后的值
}
return 0;
}
2. 火烧赤壁
题目链接:

算法原理
抛开数据范围不看,这就是一道「差分」题目:
给定一个区间,我们可以全部执行+1操作;
最后看看整个数组中,大于0的位置有多少个。
因此可以创建一个原数组的「差分」数组,然后执行完「区间修改」操作之后,还原原数组,「统计大于0」的区间长度。
但是,这道题的「数据范围」不允许我们直接差分,因为「开不了那么大」的数组;
我们发现,区间的范围虽然很大,区间的「个数」却只有2x10^4级别。此时我们就可以:
- 先将所有的「区间信息」离散化
- 然后在「离散化的基础」上,处理所有的「区间修改」操作
- 处理完之后找出「原始数组对应的区间端点」,计算相应的「长度」
实操代码
cpp
#include <iostream>
#include <vector>
#include <algorithm>
#include <unordered_map>
using namespace std;
int main()
{
int n; cin >> n;
vector<int> l(n); vector<int> r(n);
vector<int> tmp; unordered_map<int, int> m;
vector<int> f(2 * n);
for (int i = 0; i < n; i++)
{
int a, b; cin >> a >> b;
l[i] = a; r[i] = b;
tmp.push_back(a); tmp.push_back(b);
}
sort(tmp.begin(), tmp.end());
for (int i = 0; i < 2 * n; i++)
{
m[tmp[i]] = i;
}
for (int i = 0; i < n; i++)
{
f[m[l[i]]]++;
f[m[r[i]]]--;
}
for (int i = 1; i < 2 * n; i++)
{
f[i] += f[i - 1];
}
int ret = 0;
for (int i = 0; i < 2 * n; i++)
{
if (f[i] <= 0)
continue;
int j = i;
while (j < 2 * n && f[j] > 0)
j++;
ret += tmp[j] - tmp[i];
i = j;
}
cout << ret;
return 0;
}
3. 贴海报
题目链接:
算法原理
根据题意「模拟」即可。
由于「区间的长度」很大,暴力模拟的时候会超时。但是我们发现,虽然区间长度很大,但是「区间的个数」是很少的,所以我们可以「离散化」处理一下区间的端点值,然后在「离散化的基础上」模拟覆盖情况
但是离散化在离散「区间问题」的时候一定要小心!因为我们离散化操作会把区间缩短,从而导致丢失一些点。在涉及「区间覆盖」问题上,离散化会导致「结果出错」。
比如我们这道题,如果有三个区间分别为:[2,5],[2,3],[5,6],离散化之后为:。[1,3],[1,2],[3,4]
为了避免出现上述情况,我们可以在离散化的区间[x,y]时,不仅考虑x,y这两个值,也把「
+1,y+1」也考虑进去。此时「单个区间内部」就出现空隙,「区间与区间之间」也会出现空
隙。就可以避免上述情况出现。
实操代码
cpp
#include <iostream>
#include <vector>
#include <unordered_map>
#include <algorithm>
using namespace std;
int main()
{
int n, m; cin >> n >> m;
vector<int> l(m); vector<int> r(m);
vector<int> tmp; unordered_map<int, int> s;
vector<int> f(4 * m); vector<bool> st(n + 1, false);
for (int i = 0; i < m; i++)
{
int a, b; cin >> a >> b;
l[i] = a; r[i] = b;
tmp.push_back(a); tmp.push_back(a + 1); tmp.push_back(b); tmp.push_back(b + 1);
}
sort(tmp.begin(), tmp.end());
tmp.erase(unique(tmp.begin(),tmp.end()),tmp.end());
int sz = tmp.size();
for (int i = 0; i < sz; i++)
s[tmp[i]] = i;
for (int i = 1; i <= m; i++)
{
int x = s[l[i - 1]]; int y = s[r[i - 1]];
for (int j = x; j <= y; j++)
f[j] = i;
}
int ret = 0;
for (int i = 0; i < sz; i++)
{
int x = f[i];
if (x == 0 || st[x])continue;
ret++;
st[x] = true;
}
cout << ret;
return 0;
}