离散化入门

离散化可以将无穷大集合中的若干个元素映射到有限集合中以便于统计的方法。在数据范围特别大而元素个数有限我们又需要遍历的时候,可以离散化一下,注意不同题目的离散化要求可能不一样,这里给出一种比较常见的离散化代码,不同题目要做相应的修改(比如线段树区间染色要将中间加个1):

void init()
{
    sort(arr+1,arr+n+1);
    int tot=unique(arr+1,arr+n+1)-arr-1;    //去重后元素的个数
    for(int i=1;i<=tot;++i) a[i]=arr[i];
    for(int i=1;i<=tot;++i)
        printf("%d%c",a[i],i==tot?'
':' ');   
}

codeforce:670C 好题:n个人,每个人会一种语言用a来表示,有m个电影,每个电影的语音是语言b,字母是语言c,其中a,b,c都是 int 级别的,如果能听懂语音,则人很高兴,如果能看懂字幕,则比较高兴,问去看哪一个电影使得在高兴的人最多的基础上,比较高兴的人最多。

【分析】:其实思路很简单,就是遍历每一个电影,假设看这部电影,求出高兴和比较高兴的人的数量,在于之前的最大值比较一下谁大即可。但是有一个问题:就是如果直接求的话因为a,b,c都是int级别的,所以直接遍历肯定是不行的。但是m,n都是2e5级别的数据,所以可以离散化数据,查询人数的时候在二分查询即可。看代码:

#include <bits/stdc++.h>

using namespace std;
typedef pair<int,int> pii;
const int maxn=2e5+10;
int a[maxn],b[maxn],arr[maxn];
pii lan[maxn];
struct node{
    int pos,num1,num2;
}ans,temp;
int n,m,tot;
int get_id(int x)
{
    int l=1,r=tot;
    while(l<=r)
    {
        int mid=(l+r)>>1;
        if(lan[mid].first==x) return mid;
        else if(lan[mid].first<x)   l=mid+1;
        else    r=mid-1;
    }
    return 0;               
}
bool operator <(pii a,pii b){
    return a.first<b.first;
}

int main()
{
    scanf("%d",&n);
    ans.pos=1;          //先设置一下ans的位置,防止后面全都找不到输出0
    for(int i=1;i<=n;++i)   scanf("%d",&arr[i]);
    sort(arr+1,arr+n+1);
    for(int i=1;i<=n;++i){
        if(arr[i]!=arr[i-1]){
            lan[++tot].first=arr[i];
            lan[tot].second=1;
        }
        else lan[tot].second++;
    }
    sort(lan+1,lan+tot+1);
    scanf("%d",&m);
    for(int i=1;i<=m;++i)   scanf("%d",&a[i]);
    for(int i=1;i<=m;++i)   scanf("%d",&b[i]);
    for(int i=1;i<=m;++i)
    {
        int pos=get_id(a[i]);
        temp.pos=i,temp.num1=lan[pos].second;
        pos=get_id(b[i]);
        temp.num2=lan[pos].second;
        if(temp.num1>ans.num1)    ans=temp;
        else if(temp.num1==ans.num1&&temp.num2>ans.num2)  ans=temp;
    }
    printf("%d
",ans.pos);
}
原文地址:https://www.cnblogs.com/StungYep/p/12251825.html