[日常摸鱼]关于离散化

期末考回来写了一道题(大概在这篇博客之后会发出来)…需要离散化然后我写了半天才写出来…
QAQ已经是个残废选手啦

开个博客写一些离散化的东西(主要是序列上问题的离散化)

大概就算是刚学oi的oier也能看得懂了QAQ


离散化应该算是一种技巧吧…

1.经典问题:给一个长度为$n$序列,保证两两不同,求逆序对数,值域$leq 10^{18}$,$nleq 5*10^6$.

归并排序就不说了(我也没写过),一般是用树状数组做这个的吧~

但是值域这么大开不下呀怎么办呀~当然是选择离散化了

比如我们可以这样:

#define rep(i,n) for(register int i=1;i<=n;i++)
int n,w[N],rak[N];
inline bool cmp(int a,int b)
{
    return w[a]<w[b];
}
int main()
{
    scanf("%d",&n);
    rep(i,n)scanf("%d",&w[i]),rak[i]=i;
    sort(rak+1,rak+n+1,cmp);
    rep(i,n)w[i]=rak[i];
    rep(i,n)printf("%d ",w[i]);
    return 0;
}

用这样求出的$rak[i]$就表示了第$i$个位置的数的排名,然后直接赋值就可以开得下了.

不过这种方法如果有一样的数那么一样的数会有不一样的排名.

2.区间众数:一个长度为$n$的序列,多次查询区间众数,值域$leq 10^9,nleq 4*10^4$.

嗯这里只说离散化,其实非常简单啦…因为只要众数所以不管大小关系开个map随便乱搞就行了

rep(i,n)
{
    scanf("%d",&w[i]);
    if(!mp[w[i]])
    {
        mp[w[i]]=++cnt;
    }
    w[i]=mp[w[i]];
}
rep(i,n)printf("%d ",w[i]);

3.下面我们把上面两种离散化结合起来:有重复的离散化,需要保持原来的大小关系

要怎么做呢?我们可以手写一个平衡树查询排名!时间复杂度$O(nlogn)$!

记录一下有哪些数二分一下就行啦

int n,cnt,w[N],tw[N],v[N];
int main()
{
	freopen("input.in","r",stdin);
	scanf("%d",&n);
	rep(i,n)scanf("%d",&w[i]);memcpy(tw,w,sizeof w);
	sort(tw+1,tw+n+1);
	rep(i,n)if(i==1||tw[i]!=tw[i]-1)v[++cnt]=tw[i];
	rep(i,n)w[i]=lower_bound(v+1,v+cnt+1,w[i])-v;
	rep(i,n)printf("%d ",w[i]);
	return 0;
}

(这个插入代码东西不知道为什么好像挂掉了…)

当然上面的离散化方法也同样可以放在实数什么的~

以上~

原文地址:https://www.cnblogs.com/yoshinow2001/p/8410349.html