基础算法——离散化C++

一、离散化的含义

离散化就是把大而分散的一段段使用到的稀疏区间,整合映射到连续的一段较小的稠密区间里,然后就可以通过普通前缀和公式来计算连续一段的区间和,本质上就是化大为小,把稀疏离散化简为稠密连续的一段。

二、离散化面临的问题

1.可能有重复元素,去重。

vector<int> alls;
sort(alls.begin(),alls.end());
alls.erase(unique(all.begin(),alls.end()),alls.end());
//unique函数把重复元素排到尾部并返回重复元素段中第一个的指针。

2.如何算出离散化后的值。(二分法)

int findx(int x)//找到第一个大于等于x的位置
{
int left=0;
int right=alls.size()-1;
while(left<right)
{
int mid=left+right>>1;
if(alls[mid]>=x)right=mid;
else left=mid+1;
}
return right;
}

三、离散化运用实例

这一题是离散化和前缀和的结合。关键在于对函数findx映射关系的理解,下面代码中有详细注释。

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
typedef pair<int,int> PII;
const int N=300010;
int n,m;
int a[N];//储存的是数
int s[N];//前缀和
vector<int> alls;//存的所有待离散化的值
vector<PII> add,query;//用一对数来存储两种操作
int findx(int x)//findx函数用于找到a中位置x在alls中能排到第几个
{
    int left=0;int right=alls.size()-1;
    while(left<right)
    {int mid=(left+right)>>1;
        if(alls[mid]>=x)right=mid;
        else left=mid+1;
    }
    return right+1;//加1意思是映射到a中第几个(单纯为了方便后边前缀和,下标加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 left,right;
        cin>>left>>right;
        query.push_back({left,right});
        alls.push_back(left);
        alls.push_back(right);
        //alls数组储存的是a中所有待离散化值的下标
    }
    //去重
    sort(alls.begin(),alls.end());
    alls.erase(unique(alls.begin(),alls.end()),alls.end());
    //现在alls是一个有序的,无重复的储存下标的数组了
    //这题有用的就是alls中的几个下标了,其他的都没有用,这几个值差较大,把它按照顺序排好映射到a上
    //问题就转化为a数组的简单前缀和问题了,关键是映射公式findx的理解。
    for(auto item:add)
    {
        int index=findx(item.first);
        a[index]+=item.second;
    }//离散化关键步骤,把稀疏的数离散化聚集在了a上;一一映射
    for(int i=1;i<=alls.size();i++)
    {
        s[i]=s[i-1]+a[i];
    }
    for(auto item:query)
    {
        cout<<s[findx(item.second)]-s[findx(item.first)-1]<<endl;
    }//记住findx找的是a中的下标
    return 0;
}

  • 7
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值