栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

离散化的一般操作

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

离散化的一般操作

离散化看过好几次, 但是过不来多久就忘了, 所以记录一下。

原理

当题目的数据量较数据范围要小的时候采用离散化思想达到优化。
比如在数轴上有这些点: 1 000 000, 10, -1000, 1000, 20 000, 10
30 000.
这些点的个数很少, 但是范围却非常大, 如果要求某个区间上的和开的数组
会非常大,所以先对数据进行离散化处理, 离散化其实就是做一个映射, 把
较大数映射成较小数, 然后通过二分来找到这个映射值, 如果用函数表示, 就
是ind = f(val) val表示要映射的较大数, 而 ind 就是映射值, 而一般这个映射
值就是映射数组的下标。

比如上面那个例子, 离散化的过程如下:

  1. 先对所有数进行排序, 得到的结果为 -1000, 10, 10, 1000, 20 000,
    30 000, 1 000 000
  2. 在另一个数组mark中, 依次存下这些值。
    mark[] = {-1000, 10, 10, 1000, 20 000, 30 000, 1 000 000}
  3. 对mark数组进行去重, 因为映射值只会有一个。 这一步和上一步在C++
    的代码里就是一句 erase(unique(mark.begin(), mark.end()), mark.end());

上面就是离散化的过程, 后面就是怎么使用这个映射了。
首先我们定义一个find函数, 它其实就是一个二分来找位置, 这里选择用
C++中的lower_bound(), 具体定义:

int find(int val) {
	return lower_bound(mark.begin(), mark.end(), val) - mark.begin();
}

lower_bound是返回数组第一个大于等于val的迭代器(相当于一个指针), 然后减去第一个元素的迭代器就是下标了。

最后附上一道acWing上的模板题: 
假定有一个无限长的数轴,数轴上每个坐标上的数都是 0。

现在,我们首先进行 n 次操作,每次操作将某一位置 x 上的数加 c。

接下来,进行 m 次询问,每个询问包含两个整数 l 和 r,你需要求出在区间 [l,r] 之间的所有数的和。

输入格式
第一行包含两个整数 n 和 m。

接下来 n 行,每行包含两个整数 x 和 c。

再接下来 m 行,每行包含两个整数 l 和 r。

输出格式
共 m 行,每行输出一个询问中所求的区间内数字和。

数据范围
−109≤x≤109,
1≤n,m≤105,
−109≤l≤r≤109,
−10000≤c≤10000
输入样例:
3 3
1 2
3 6
7 5
1 3
4 6
7 8
输出样例:
8
0
5
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;

#define mst(a, b) memset(a, b, sizeof(a))
typedef long long ll;
typedef pair pii;
const int maxn = 300000 + 10;
const int inf = INT32_MAX;

int n, m;
vector p, q;
vector mark;
ll pre[maxn];

int find(int val) {
    return lower_bound(mark.begin(), mark.end(), val) - mark.begin() + 1;
    // 这里 + 1是因为前缀和数组是从下标1开始的
}

int main() {
    std::ios::sync_with_stdio(false);
    cin >> n >> m;
    for (int i = 0; i < n; i++) {
        int x, c;
        cin >> x >> c;
        mark.push_back(x);
        p.push_back({x, c});
    }
    for (int j = 0; j < m; j++) {
        int l, r;
        cin >> l >> r;
        mark.push_back(l);
        mark.push_back(r);
        q.push_back({l, r});
    }

    sort(mark.begin(), mark.end());
    mark.erase(unique(mark.begin(), mark.end()), mark.end());

    for (auto it : p) {
        pre[find(it.first)] += it.second;
    }

    for (int i = 1; i <= mark.size(); i++) {
        pre[i] += pre[i - 1];
    }
    for (auto it : q) {
        cout << pre[find(it.second)] - pre[find(it.first) - 1] << endl;
    }

    return 0;
}
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/511080.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号