离散化学习

本文探讨了如何处理值域巨大且元素个数较少的数组离散化问题,使用C++的STL函数实现去重,并介绍了一种基于二分查找的离散化方法。同时,博客详细讲解了一个涉及区间操作的场景,包括对无限长数轴上的数进行多次操作后,处理查询区间内数字和的问题。
摘要由CSDN通过智能技术生成

算法:

值域大(开一个很大的数组不可能),个数少:例如:值域0~10^9,个数:10^5

离散化:例:将一个数组a[]:1,3,100,2000,500000

将上列数组中的每个数映射到:0,1,2,3,4。

问题:

1.a[]中可能有重复元素,去重(以下代码):

vector<int> alls; //存储所有待离散化的值
sort(alls.begin(),alls.end());//排序
alls.erase(unique(alls.begin(),alls.end()),alls.end()) //去掉重复元素

/*  "unique"是C++语言中的STL函数,包含于<algorithm>头文件中。功能是将数组中相邻的重复元素去除。然而其本质是将重复的元素移动到数组的末尾,最后再将迭代器末尾指向最后不重复的下标。*/
// erase的用法
#include <iostream>
#include <vector>

int main ()
{
  std::vector<int> myvector;

  // set some values (from 1 to 10)
  for (int i=1; i<=10; i++) myvector.push_back(i);

  // erase the 6th element
  myvector.erase (myvector.begin()+5);  //指向要从中移除的单个元素的迭代器矢量 

  // erase the first 3 elements:
  myvector.erase (myvector.begin(),myvector.begin()+3);
    /*最后
迭代器指定矢量]要删除:[第一个,最后一个)也就是说,范围包括第一和最后的,包括第一但不是指的那个最后的 .
成员类型迭代器和常数迭代器是随机迭代器指向元素的类型*/
  std::cout << "myvector contains:";
  for (unsigned i=0; i<myvector.size(); ++i)
    std::cout << ' ' << myvector[i];
  std::cout << '\n';

  return 0;
}

结果:myvector contains: 4 5 7 8 9 10

补充:

c.erase(p)--从c中删除迭代器p指定的元素,p必须指向c中的一个真实元素,不能等于c.end()
c.erase(b,e)--从c中删除迭代器对b和e所表示的范围中的元素,返回e


 

2.如何算出a[i]中的值离散化后的值:二分

//二分求出x对应的离散化的值


int find (int x)  //找到第一个大于等于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,……,n,不+1就从0开始
}

pair:C++ std::pair的用法_吉大秦少游的博客-CSDN博客_std::pair

 题目:

假定有一个无限长的数轴,数轴上每个坐标上的数都是 00。

现在,我们首先进行 nn 次操作,每次操作将某一位置 xx 上的数加 cc。

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

输入格式

第一行包含两个整数 nn 和 mm。

接下来 nn 行,每行包含两个整数 xx 和 cc。

再接下来 mm 行,每行包含两个整数 ll 和 rr。

输出格式

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

数据范围

−109≤x≤109−109≤x≤109,
1≤n,m≤1051≤n,m≤105,
−109≤l≤r≤109−109≤l≤r≤109,
−10000≤c≤10000−10000≤c≤10000

输入样例:

3 3
1 2
3 6
7 5
1 3
4 6
7 8

输出样例:

8
0
5

代码: 

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;

typedef pair<int,int> PII;  //结构体实现 用first和second 访问第一个和第二个值

const int N=3e5+10;

int n,m;
int a[N],s[N];
vector<int> alls;  //离散化的容器
vector<PII> add,query;    //加入的数和查询

int find(int x)    //找到第一个大于等于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开始
}


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 a:b)中b为一个容器,效果是利用a遍历并获得b容器中的每一个值,但是a无法影响到b容器中的元素。

    for(auto &a:b)中加了引用符号,可以对容器中的内容进行赋值,即可通过对a赋值来做到容器b的内容填充。
    */
    
    //插入处理
    for(auto item : add)
    {
        int x=find(item.first);   //将存入数的离散化后的位置放入x数组中
        a[x]+=item.second;      //将数放入对应的离散化的位置
    }
    //预处理前缀和
    for(int i=1;i<=alls.size();i++) s[i]=s[i-1]+a[i];  //因为通过离散化使那些数对应的坐标会变小,因此到size就够了
    //处理询问
    for(auto item : query)
    {
        int l=find(item.first),r=find(item.second);    //里面会有好多的数为0,所以前缀和的值不影响
        cout<<s[r]-s[l-1]<<endl;
    }
    
    
    return 0;
    
}

理解:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值