离散化
-
应用场景:数组很大,但使用的数个数很少,即分布分散。如:
//有大数组 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;
}









