离散化

109 阅读2分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。 离散化,简单来说就是将一些分散不集中的点经过映射,让这些点不改变原来顺序,让其集中起来。

举个例子:
在这里插入图片描述
离散化的操作:排序->去重

	//s储存的是需要离散的值
	sort(s.begin(), s.end());
	s.erase(unique(s.begin(), s.end()), s.end())

对于离散化的用途:再举一个非常极端的例子,假设有1000个数,分布在[0, 10 ^ 9],我要对区间[l, r]询问区间和,你被要求用前缀和做,那你难道要开一个10 ^ 9的数组吗,这显然是行不通的。
然后我们可以将其离散化,将这一千个数的下标离散到[1,1000],这样我们只需要维护一个1000的数组了!!!

一道小小的模板不成敬意区间和

在这里插入图片描述
本题的情况就像我上面所说的那样,范围很大,但是数比较少,我们维护一个alls的向量保存需要访问的下标,然后排序去重,就映射到一个小数组了。

答案是从Y总那学的

#include <bits/stdc++.h>

using namespace std;

typedef pair<int, int> PII;
const int N = 300010;//需要离散的个数

int n,m;
int a[N],s[N];//a储存离散化后的数组,s为其前缀和
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;//映射到1,2,3,4,...
}

int main()
{
    cin>>n>>m;
    for(int i = 0; i < n; i++)
    {
        int x, c;
        scanf("%d%d", &x, &c);
        add.push_back({x, c});//存入操作
        alls.push_back(x);//将涉及的坐标存入
    }

    for(int i = 0; i < m; i++)
    {
        int l, r;
        scanf("%d%d", &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;
}