ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

离散化

2021-12-26 19:06:22  阅读:153  来源: 互联网

标签:end int back 离散 vector alls 100


背景:离散化一词常常见到,甚至很多算法题不自觉的都会用到,比如hashmap,根据value找key等(内置find效率较低),根据acwing的例题总结了一下:

例题:https://www.acwing.com/problem/content/804/

所谓离散化,就是将一些定义域很大的数,但总数较小,就可以映射到一个新的数组。

假设我们从输入中得到案例的key-value,往往想搞成以下类似形式:

{0,1},{1,100},{2,1000},{3,2234},{4,99999999},{5,100}...

但是题设是这样的形式

{1,?},{100,?},{1000,?},{2234,?},{99999999,?},{100,?}...

ps.每对数中第一个为数组下标,第二个是增加值的大小

这样的k-v关系使得我们很难创建一个如此之大的数组空间。于是得从数据结构下手,创建vector<pair<int,int>>,批量地增加值再输出区间和 ,我们可以使用前缀和来有效降低轮询时间复杂度。


我们将k-v关系保存在一个存储pair的vector 记为add[]

vector value {{1,0},{100,2},{1000,3},{2234,3},{99999999,4},{100,5}...}

vector key 0 1 2 3 4 5

再单独创建数组记为alls[]={1,100,1000,2234,999999999,100}

我们注意到此时alls[]有两个相同的值,一般情况下我们可能会需要对alls进行去重。(sort+erase(unique,end))

方式一:sort+unique

vector <int> v;
sort(v.begin(),v.end());
v.erase(unique(v.begin(),v.end()),v.end);

unique(it1,it2);//先将所有重复元素排在尾部,返回第一个重复元素的指向迭代器

方式二:生成时count()==0判断是否有,无重复再push_back。

去重后:alls[]={1,100,1000,2234,99999999} 此时值就是唯一

此时如果遍历 add, it.first 即为值,本题中我们将it.second设为累加值

体现离散化思想的操作来了:

我们使用一个 int find(int value)函数来返回一个 (0,1,2,...n)区间的值。传入it.first(这里是找下标操作,可以用stl里面的find内置函数解决,但复杂度高)

构造a[N]存储累加值,大小由key范围决定

i 1 2 3 4 2.....

a[i] 100 40 22 12 40......

(it.first,it.second) {1,100} {100,20} {1000,22} {2234,12} {100,20}...... (先看这一排,再去找i,a[i])

s[i] 100 120 142 154....

ps. i=2时a[i]和it.second不等是因为有重复的it.first=100;

最后前缀和就可以用在轮询区间和上了。

讲了这么多,其实一个图就能讲明白.jpg:

​ |---------------------------------|----------------------------------|

索引: -777777 -1 0 1 999999

转换为:

​ |{-777777,?} {-1,?} {1,?} {9999999 ,?}|

​索引: 0 1 2 3

加上

​ {-777777 ,-1 , 0 , 1 , 999999}

代码:

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

typedef pair<int, int> PII;

const int N = 300010;

int n, m;
int a[N], s[N];

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()
{
    cin >> n >> m;
    for (int i = 0; i < n; 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 (auto item : add)
    {
        int x = find(item.first);
        a[x] += item.second;
    }

    // 预处理前缀和
    for (int i = 1; i <= alls.size(); i ++ ) s[i] = s[i - 1] + a[i];

    // 处理询问
    for (auto item : query)
    {
        int l = find(item.first), r = find(item.second);
        cout << s[r] - s[l - 1] << endl;
    }

    return 0;
}

标签:end,int,back,离散,vector,alls,100
来源: https://www.cnblogs.com/rabbithacker/p/15733695.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有