基础算法12——离散化

离散化

  • 应用场景:数组很大,但使用的数个数很少,即分布分散。如:

    //有大数组
    const int N=1e19;
    int a[N];
    //但是需要用到的a[]只有1e5个元素。
    //即 元素分布很分散。
    //如:当a[]只需要a[1]、a[10000]、a[100000]、a[10000000],4个数时,
    //这4个数分布很分散,∴可以离散化处理。
  • 离散化处理:

    数组映射保存:

    a[1] ——> a[1];
    a[10000] ——> a[2];
    a[100000] ——> a[3];
    a[10000000] ——> a[4];
  • 例题:区间和

    Subject:
    假定有一个无限长的数轴,数轴上每个坐标上的数都是 0。
    现在,我们首先进行 n 次操作,每次操作将某一位置 x 上的数加 c。
    接下来,进行 m 次询问,每个询问包含两个整数 l 和 r,你需要求出在区间 [l,r] 之间的所有数的和。
    输入格式:第一行包含两个整数 n 和 m。
            接下来 n 行,每行包含两个整数 x 和 c。
            再接下来 m 行,每行包含两个整数 l 和 r。
    输出格式:共 m 行,每行输出一个询问中所求的区间内数字和。
    数据范围
    −1e9≤x≤1e9;1≤n,m≤1e5;−1e9≤l≤r≤1e9;−10000≤c≤10000

    解题思路

    1.构造数轴:1)创结构体储存a[]映射数组的两个元素:x(原数组位置) 和 c(需要加的 值); (共k个,k最终=n)

    2)基于x对a[]快速排序

    3)利用双指针对a[]去重。

    2.利用二分查找,找到l==x && r==x 的k值,相当于在映射数组中找到原数组中的对应位置。

    3.利用前缀和对映射数组求区间。

eg.
#include<stdio.h>
​
typedef struct
{
     int num;//储存原数组下标x
     int value;//储存c
}ARRAY;
​
ARRAY a[100009];
int s[100009], n, m;
​
void quick_sort(int l, int r)
{
     if (l >= r)return;
     int i = l - 1, j = r + 1, x = a[(l + r) / 2].num;
     while (i < j)
     {
          do i++; while (a[i].num < x);
          do j--; while (a[j].num > x);
          if (i < j)
          {
               //将结构体中的所有元素整体交换
               ARRAY t = a[i];
               a[i] = a[j];
               a[j] = t;
          }
     }
     quick_sort(l, j);
     quick_sort(j + 1, r);
}
​
//对a[].num二分查找,找到左右区间所在映射数组的位置
int bsearch_l(int x)
{
     int l=1,r=n,mid;
     while (l < r)
     {
          mid = (l + r) / 2;
          if (a[mid].num>=x)
          {
               r = mid;
          }
          else
          {
               l = mid + 1;
          }
     }
     if (x <= a[l].num)
     {
          return l;
     }
     else
     {
          return n+1;//x超过最大值//保证l-1=n
     }
}
​
int bsearch_r(int x)
{
     int l = 1, r = n, mid;
     while (l < r)
     {
          mid = (l + r+1) / 2;
          if (a[mid].num<=x)
          {
               l = mid;
          }
          else
          {
               r = mid-1;
          }
     }
     if (x >= a[l].num)//x小于最小值
     {
          return l;
     }
     else
     {
          return 0;
     }
}
​
int main()
{
     scanf("%d %d", &n, &m);
​
     //构造映射数组
     int i, j;
     for (i = 1; i <= n; i++)
     {
          scanf("%d %d", &a[i].num, &a[i].value);
     }
     //对a[].num快速排序
     quick_sort(1, n);
     //双指针对a[].num去重
     for (i = 2, j = 1; i <= n; i++)
     {
          if (a[i].num == a[j].num)
          {
               a[j].value += a[i].value;
          }
          else
          {
               a[++j] = a[i];//整体替换
          }
     }
     n =j;//去重之后的新长度
​
     //求前缀和
     for (i = 1; i <= n; i++)
     {
          s[i] += s[i - 1] + a[i].value;
     }
​
     //询问区间
     int l, r;
     while (m--)
     {
          scanf("%d%d", &l, &r);
          l = bsearch_l(l);
          r = bsearch_r(r);
          printf("%d\n", s[r] - s[l-1]);
     }
​
     return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值