<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>算法计划 on 出口は直ぐ其処</title><link>https://tsugihagidake.github.io/categories/%E7%AE%97%E6%B3%95%E8%AE%A1%E5%88%92/</link><description>Recent content in 算法计划 on 出口は直ぐ其処</description><generator>Hugo -- gohugo.io</generator><language>zh-CN</language><lastBuildDate>Mon, 19 Oct 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://tsugihagidake.github.io/categories/%E7%AE%97%E6%B3%95%E8%AE%A1%E5%88%92/index.xml" rel="self" type="application/rss+xml"/><item><title>离散化</title><link>https://tsugihagidake.github.io/post/acmplan-%E7%A6%BB%E6%95%A3%E5%8C%96/</link><pubDate>Mon, 19 Oct 2026 00:00:00 +0000</pubDate><guid>https://tsugihagidake.github.io/post/acmplan-%E7%A6%BB%E6%95%A3%E5%8C%96/</guid><description>&lt;img src="https://tsugihagidake.github.io/" alt="Featured image of post 离散化" /&gt;&lt;p&gt;关于离散化的一些笔记&lt;/p&gt;&#10;&lt;p&gt;学习参考https://www.cnblogs.com/cytus/p/8933597.html&lt;/p&gt;&#10;&lt;p&gt;尝试用自己的话梳理一下&lt;/p&gt;&#10;&lt;h1 id="离散化"&gt;离散化&#10;&lt;/h1&gt;&lt;p&gt;如果我们遇到一道题，已知里面有很多个可重复的数，不同的数最多有100种，范围在1~10^12不等。我们需要记录每个数出现的次数，但是分配的内存空间不允许我们直接开10^12这么大的数组，所以出现的数本身无法作为下标。这个时候如果题目中数仅相对大小存在意义，我们就可以将它们进行离散化处理之后再用100的数组来储存。&lt;/p&gt;&#10;&lt;p&gt;比如数组{3,6,1,9}离散化之后处理为{1,2,0,3}&lt;/p&gt;&#10;&lt;p&gt;处理之后范围更小的数常用来做数组下标，在并查集、线段树等情境下也有应用&lt;/p&gt;&#10;&lt;p&gt;写的时候突然想到，如果是小数等不允许被用来做下标的元素，条件允许的话也可以用离散化只存储相对大小&lt;/p&gt;&#10;&lt;p&gt;流程如下：&lt;/p&gt;&#10;&lt;h2 id="通用方法"&gt;通用方法&#10;&lt;/h2&gt;&lt;h3 id="一复制数组"&gt;一、复制数组&#10;&lt;/h3&gt;&lt;p&gt;首先假设我们拥有一个输入的数组，数组中的数本身不允许我们用来直接做下标。我们先用数组a把他们的值存起来，然后复制一份到数组t。&lt;/p&gt;&#10;&lt;p&gt;为方便去重，我们使用从0开始的下标。&lt;/p&gt;&#10;&lt;p&gt;作为例子，我们假设数最多有n种，数的范围最大为10^9 &lt;del&gt;（方便写int）&lt;/del&gt; ，那么现在我们有：&lt;/p&gt;&#10;&lt;pre tabindex="0"&gt;&lt;code&gt;vector&amp;lt;int&amp;gt; a;&#10;&#10;vector&amp;lt;int&amp;gt; t = a;//与a数组内容相同&#10;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="二数组排序并去重视情况"&gt;二、数组排序并去重（视情况）&#10;&lt;/h3&gt;&lt;p&gt;如果输入的数组中没有重复元素，直接使用sort进行排序即可：&lt;/p&gt;&#10;&lt;pre tabindex="0"&gt;&lt;code&gt;sort(t.begin(),t.end());//默认升序&#10;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;如果输入的数组中有重复元素，我们就需要先进行排序，再进行&lt;strong&gt;复制数组中&lt;/strong&gt;的去重。&lt;/p&gt;&#10;&lt;p&gt;不去重会导致离散化编号之间存在空缺，造成浪费。&lt;/p&gt;&#10;&lt;p&gt;我们使用unique函数对复制之后的数组t进行去重：&lt;/p&gt;&#10;&lt;p&gt;unique用法：unique(t.begin(), t.end())，返回去重后数组的尾地址的后一格。unique在被使用后会将不重复元素依次移到前面，因此不会打乱原来的排序。同时，后面的不需要的重复元素需要用erase清除。&lt;/p&gt;&#10;&lt;pre tabindex="0"&gt;&lt;code&gt;sort(t.begin(),t.end());//先进行升序排序&#10;&#10;t.erase(unique(t.begin(),t.end()),t.end());//先执行unique再执行erase&#10;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="三离散化处理进入新数组"&gt;三、离散化处理进入新数组&#10;&lt;/h3&gt;&lt;p&gt;t数组已经排序并且没有重复元素，此时t数组的下标的相对大小与元素的相对大小一样，并且下标数据小没有空间浪费，我们就可以让t数组的下标成为对应元素的离散化编号。&lt;/p&gt;&#10;&lt;p&gt;问题来了，我们发现t数组中的元素的顺序和a数组不一样了，同时重复的元素也没有了，很显然无法直接作为处理后的a数组来进行使用。那我们应该怎么把原数组a中的元素用他们相应的离散化编号来替代并存入新的数组呢？&lt;/p&gt;&#10;&lt;p&gt;（这里可以将离散化编号直接塞回原数组a）&lt;/p&gt;&#10;&lt;h3 id="四lower_bound二分查找的办法通用"&gt;四、lower_bound二分查找的办法（通用）&#10;&lt;/h3&gt;&lt;p&gt;原理是按照a数组的下标从小到大去看，去找a数组数据在t中的位置，将t对应的位置下标存入新数组的a数组对应的下标中。我们之前已经知道了，t数组中数据的位置就是他们的离散化编号。&lt;/p&gt;&#10;&lt;p&gt;流程大概是这样的：&lt;/p&gt;&#10;&lt;p&gt;a[x] -&amp;gt; lower_bound发现t[y] = a[x] -&amp;gt; result[x] = y&lt;/p&gt;&#10;&lt;p&gt;有代码：&lt;/p&gt;&#10;&lt;pre tabindex="0"&gt;&lt;code&gt;vector&amp;lt;int&amp;gt; result(n);&#10;&#10;for(int i = 0; i &amp;lt; n; i++ )&#10;{&#10; result[i] = lower_bound(t.begin(),t.end(),a[i]) - t.begin();&#10;}&#10;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="补充方法用pair事先保存原下标不需要t数组简单版本无法处理元素重复的情况"&gt;补充方法：用pair事先保存原下标（不需要t数组，简单版本无法处理元素重复的情况）&#10;&lt;/h2&gt;&lt;p&gt;我们直接从一开始的a数组开始处理即可。这种方法不用普通的t数组，而是使用pair数组作为辅助数组。&lt;/p&gt;&#10;&lt;p&gt;这种方法的思路是在存储原值的同时，也保存这个值在原数组中的下标。这样可以替代方法一中搜索的过程。这种方法因为省去了二分查找的过程直接写回所以速度较快，但是下面给出的是简单版本，不能直接处理重复元素。此处我们使用pair存储之后会直接排序，把顺序当做离散化编号，不会去重。&lt;/p&gt;&#10;&lt;p&gt;有重复元素的话，遍历values遇到重复元素就特殊处理一下（如果当前元素的first和前一个元素相同，就让它继续使用前一个元素的离散化编号；如果不同，编号才加一。）的写法也可以。&lt;/p&gt;&#10;&lt;p&gt;这种方法需要建一个新的pair数组values，根据原数组a来存储原值和原下标。&lt;/p&gt;&#10;&lt;pre tabindex="0"&gt;&lt;code&gt;vector&amp;lt;pair&amp;lt;int,int&amp;gt;&amp;gt; values;&#10;&#10;for(int i = 0; i &amp;lt; n; i++ )&#10;{&#10; values.push_back({a[i] , i});&#10;}&#10;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;我们依据values存储的原下标和原值的对应关系来进行操作。流程：&lt;/p&gt;&#10;&lt;p&gt;values按照first排序 -&amp;gt; y是离散化编号 -&amp;gt; values[y].second是该元素的原下标 -&amp;gt; result[values[y].second] = y&lt;/p&gt;&#10;&lt;pre tabindex="0"&gt;&lt;code&gt;sort(values.begin(),values.end());//pair数组默认按pair的前值升序排序&#10;&#10;for(int i = 0; i &amp;lt; n; i++ )&#10;{&#10; result[values[i].second] = i;//将序号，即离散化编号赋值给结果数组原下标的位置，使离散化编号i替代相应的原值&#10;}&#10;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;自此，离散化完成。我们从原数组a得到了新的结果数组result，现在我们可以使用result数组中的较小的元素在我们需要的地方作为下标了。&lt;/p&gt;&#10;</description></item></channel></rss>