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