[日常摸鱼]关于离散化

本文详细介绍了离散化的几种常见技巧,包括解决逆序对数问题的经典离散化方法、区间众数问题的离散化处理,以及如何结合两者进行有重复元素的离散化,保持原有大小关系。通过实例代码展示了离散化在处理大数据范围问题时的有效性和灵活性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

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

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

 


 

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

1.经典问题:给一个长度为$n$序列,保证两两不同,求逆序对数,值域$\leq 10^{18}$,$n\leq 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,n\leq 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/yoooshinow/p/8410349.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值