0
点赞
收藏
分享

微信扫一扫

【算法基础课模板笔记+注释】 基础算法12 --- 离散化

是波波呀 2022-02-18 阅读 83

声明

本文资料参考acwing算法基础课
地址:https://www.acwing.com

概述

  1. 解决问题:把下标范围很大但是多数无效的数组,映射到一个较短的数组
  2. 和一般的哈希表不同,这里下标必须保持有序(对应map)
  3. 查找时间复杂度为O(logn),(使用二分)
  4. 思路:把有用的下标存到一个数组中,内容存到另一个数组中,这两个数组一一对应,使用二分查找原下标对应的新下标

模板记忆

开设数组:

  1. alls:记录原下标
  2. a[N]:记录对应下标的内容
  3. s[N]:附加的使用前缀和求范围数大小
  4. add,query:存储各种操作的数组,由于确定alls前必须把所有有用的数都存下来,所以不同用途的数字分开保留

这个模板分为四个部分:

  1. 去重:把一切可能用到的数字放入alls,然后去重
  2. 插入内容:用原下标查找新下标并插入内容数组
  3. 查找:根据原下标求新下标(二分)

模板代码

// 1所有用用的数字放入alls后,用以下语句去重
sort(alls.begin(), alls.end());
alls.erase(unique(alls.begin(), alls.end()), alls.end());

// 2插入数组内容
for (int i = 0; i < n; i ++ )
{
    int tag = find(add[i].first);
    a[tag] += add[i].second;
}

// 3输入原下标,查找新下标
int find(int x)
{
    int l = 0, r = alls.size() - 1;
    while (l < r)
    {
        int mid = l + r >> 1;
        if (alls[mid] == x) return mid + 1;
        else if (alls[mid] < x) l = mid + 1;
        else r = mid - 1;
    }
    return l + 1;  // 这里返回的是+1是因为要用前缀和
}

离散化 — 区间和

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
typedef pair<int, int> PII;
const int N = 300010;
int a[N], s[N];
vector<PII> add, query;
vector<int> alls;
int find(int x)  // 根据原下标查新下标,二分法
{
    int l = 0, r = alls.size() - 1;
    while (l < r)
    {
        int mid = l + r >> 1;
        if (alls[mid] == x) return mid + 1;
        else if (alls[mid] < x) l = mid + 1;
        else r = mid - 1;
    }
    return l + 1;
}
int main()
{
    int n, m;
    cin >> n >> m;
    for (int i = 0; i < n; i ++ )
    {
        int x, c;
        cin >> x >> c;
        add.push_back({x, c});  // 把所有加存在add里
        alls.push_back(x);  // 对应下标存起来
    }
    for (int i = 0; i < m; i ++ )
    {
        int l, r;
        cin >> l >> r;
        query.push_back({l, r});  // 把所有查找存在query里
        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 < n; i ++ )
    {
        int tag = find(add[i].first);
        a[tag] += add[i].second;
    }
    // 前缀和
    for (int i = 1; i <= alls.size(); i ++ ) s[i] = a[i] + s[i - 1];
    // 进行查找操作
    for (int i = 0; i < m; i ++ )
    {
        int l = find(query[i].first);
        int r = find(query[i].second);
        cout << s[r] - s[l - 1] << endl;
    }
    return 0;
}

举报

相关推荐

0 条评论