离散化处理
什么是离散化呢?比如有这么一道题:
题目描述
小鱼有 n 名优秀的粉丝。
粉丝们得知小鱼将会在一条直线上出现,打算去膜他。为了方便,粉丝们在这条直线上建立数轴。
第 i 名粉丝有一个侦查区间[li,ri] 。如果小鱼在 j(li≤j≤ri) 处出现,这名粉丝将立刻发现并膜他。
小鱼希望膜他的人越多越好,但是他不能分身,因此只能选择一个位置出现。
小鱼想知道自己最多能被多少个人膜。
输入
第一行一个整数n —— 粉丝的个数。
接下来 n 行,每行两个整数 li,ri ,分别表示第 i 名粉丝的侦查区间的两个端点。两个数之间用空格隔开。
输出
共一行,一个整数,表示小鱼最多能被多少人膜。
样例输入
4
3 5
4 8
1 2
5 10
样例输出
3
提示
样例解释:
如图所示,小鱼可出现在5处,此时第1,2,4号粉丝可以膜他。小鱼最多只能被3个粉丝膜。
对于20%的数据,n≤2
对于60%的数据,n≤2000
对于100%的数据,1 ≤ n ≤ 5 × 104,1 ≤ li ≤ ri <230
输入的数据不超过 5e4,但是后面的区间范围却很大;
按照以前的思想,应该是进行差分处理,但是却因为数据范围太大而无法进行寻常的差分处理,这时就可以进行离散化处理;
离散化:比如输入的有6个数 ,分别为: 1 9 100000000000 9999999999999999999 12312352346541236471263 1234
经过离散化之后这6个数分别代表 1 2 4 5 6 3
因此可以看出将数据从小到大进行排序,然后每个数可以换成排序之后的数组的小标,这样不会影响相互之间的大小关系,这样一来,就可以使得以前比较大的数据范围缩小了很大一部分,正适合我们的意愿,但是可能有同一个数据出现若干次的情况,这次就要进行去重处理
比如有 六个数分别为: 1 9 9999999999999999999 9999999999999999999 123123312312352346541236471263 9999999999999999999
那么这六个数进行离散化就变成了:
1 2 3 3 4 3
因此离散化一般的过程就是: 排序去重
经常用STL里面的不定长数组,sort一遍之后,然后进行去重
vet.erase(unique(vet.begin(),vet.end()),vet.end());
erase用于删除元素,常用的用法是:
vec.erase(vec.begin()+i,vec.end()+j);删除区间[i,j-1];区间从0开始
unique的作用是“去掉”容器中相邻元素的重复元素(不一定要求数组有序),它会把重复的元素添加到容器末尾(所以数组大小并没有改变),而返回值是去重之后的尾地址,下面举个例子。
具体的话可以看巨巨的博客
unique函数的去重过程实际上就是不停的把后面不重复的元素移到前面来,也可以说是用不重复的元素占领重复元素的位置。处理完之后,他的返回值是一个迭代器,它指向的是去重后容器中不重复序列的最后一个元素的下一个元素。
unique 返回的是最后一个去重完之后的元素的下一个元素,而erase的时候,正好是将从这个元素开始到end的所有重复元素进行删除
细心的小伙伴此时可能已经发现了,运用上面的两个函数一起使用就可以达到真正的去重功能,因为erase之后直接将多余的元素进行删除了,容器的size也减小了
而用lower_bound二分后面的操作得到的下标就正好是第几个元素,此时的下标就是每个元素对应的相对大小,也就是第几大或者是第几小
以上的参考代码为:
ll maxx=-1,minn=inf;
ll num[maxn],a[maxn],num2[maxn];
ll res,ans;
int n;
ll cnt[maxn];
pair<ll,ll> together[maxn];
vector <ll> vet;
int main()
{
n=read;
for(int i=1;i<=n;i++){
ll left=read,right=read;
vet.push_back(left);
vet.push_back(right);
together[i]={left,right};
}
sort(vet.begin(),vet.end());
vet.erase(unique(vet.begin(),vet.end()),vet.end());
for(int i=1;i<=n;i++){
ll left=together[i].first;
ll right=together[i].second;
ll templeft=lower_bound(vet.begin(),vet.end(),left)-vet.begin();
ll tempright=lower_bound(vet.begin(),vet.end(),right)-vet.begin();
num[templeft]+=1;
num[tempright+1]-=1;
}
int len=vet.size();
for(int i=1;i<len;i++) num[i]+=num[i-1];
ans=num[0];
for(int i=1;i<len;i++) if(num[i]>=ans) ans=num[i];
cout<<ans<<endl;
return 0;
}