什么是离散化?
把无穷大集合中的若干个元素映射为有限集合,以便于统计的方法;
在不改变数据相对大小的情况下,对数据进行相应的缩小。
例:(1)处理前:1,23,114514,999.
我们按从小到大进行标号。1标为0,23标为1,999标为2,114514标为3.
处理后:0,1,3,2.
(2)处理前:{100,200} ,{20,50000},{1,400};
同样方法处理。
处理后:{2,3} {1,5 } {0,4 }
离线化前提:1.问题只涉及有限个数值。
2.问题与数值的绝对大小无关,只与相对顺序有关。
在csdn曹老师阿看到了一个很好就能解释的例子,借用一下
举个例子,如果一个坐标轴很长(>1e10),给你1e4个坐标,询问某一个点,坐标比它小的点有多少。
很容易就知道,对于1e4个点,我们不必把他们在坐标轴上的位置都表示出来,因为我们比较有多少比它小的话,只需要知道他们之间的相对大小就可以,而不是绝对大小,这,就需要离散化。
如何进行离散化
函数:unique sort
unique的作用是去重,但是去重前要先进行排序,保证重复元素相邻
sort(b,b+n);
m = unique(b,b+n) - b;
m代表的是去重后的元素个数
返回值:背后值得第一个元素的“首地址”
比如排序完数组里为 0 1 6677 123456789 6677 6677 123456789
那么此时的返回值就为标红的6677,-b的原因是删去返回值。
注意:1.unique执行的不是删除重复项而是用不重复的元素替换了重复元素。
一种常用的离散化去重方法:
1.排序
2.去重
3.索引元素离散化后对应的值
-b的作用参照上面
什么是前缀和
为什么要用前缀和
即把很多次加法转换为一次减法,降低时间复杂度
#include <bits/stdc++.h>
using namespace std;
const int N=1e6 + 10;
long long sum[N],a[N];
int main()
{
long long n;
long long l,r;
long long ans;
scanf("%lld",&n);
//预处理
for(int i=1;i<=n;i++)
{
sum[i]=sum[i-1]+a[i];
}
//--------------------------------
//求值
scanf("%lld %lld",&l,&r);
ans=0;
ans= sum[r] - sum[l-1];//前r项和减去前l-1项和
}
二维前缀和
比如我们要去sum[x][y]即求下图有颜色的区域可以用绿色区域加上粉色区域减去橙色区域再加上红色区域
其中绿色区域=图上可见绿色区域+橙色区域
同理粉色区域=图上可见粉色区域+橙色区域
同理我们可以求各个区域的和