随便说说——离散化

Posted fallen-down

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了随便说说——离散化相关的知识,希望对你有一定的参考价值。

本文并非完全原创,引用的其他博客的代码详见最下方。若有侵权行为会第一时间修改。

前记——

最近机房考试,周围的大佬都用了巧妙的方法做了一道我认为需要离散化(而且当时我还不会)(尽管现在也好不到哪里去)的题目

本蒟蒻十分荣幸的因此WA了。所以我决定将错就错,不去想正解了,在岔路上且行且歌

—————————————————————————————————————前置内容—————————————————————————————————————————

  • 为什么要离散化

当题目中给你一个数据,你想要以此为根基开数组,你应该怎么办

  1. 抱头苦想,换一种算法,规避这个数组(CDQ//利用数据结构优化//用bool)
  2. 离散化大法好
  • 离散化前提

  1. 你数组开不下了
  2. 但你在计算中,只在意元素之间的相对大小,但不在意其真实大小时

 

——————————————————————————————————————正文——————————————————————————————————————————

这篇文章要收录三种离散化的方式。下面我将以我自己的使用频率来一一介绍(其实并没有用过太多)

  • STL——map

不知道怎么说明,先设置一个小情景吧:

          有标号N(N<=1,000,000,000)的人,任意(每个号可能被抽中两次)抽出25个人,问谁被抽中次数最多;

首先你不可能成为桶哥,其次你要直接用map存我也拦不住你,可我们在搞离散化,所以,,,

for(i=1;i<=n;i++){
  scanf("%d",&kc);
  if(!a.count(kc)) {
       ff++;
      a[kc]=ff;
      f[ff]++;
   }
  f[a[kc]]++;
}

 

 

 

 

首先输入人的编号——kc,其次再看map<int,int>a 中是否出现过;

如果没有出现过,(ff++)——代表新出现一个数,他的编号就是他是第几个新出现的;

 

 

如果出现过,则把kc离散好的数fff的桶中++,代表出现次数+1;

优点——好写

缺点——时间复杂度比下面两种高

  • unique函数法

你不会这个函数我也救不了你,自己学吧

这个好说——包含重复元素,并且相同元素离散化后也要相同

 1 const int maxn=1e5+10;
 2 int a[maxn], t[maxn], b[maxn];
 3 int n;
 4 scanf("%d",&n);
 5 for(int i=1; i<=n; i++)
 6     scanf("%d",a[i]),t[i]=a[i];
 7 sort(t+1,t+n+1);
 8 m=unique(t+1,t+1+n)-t-1;//求出的m为不重复的元素的个数
 9 for(int i=1; i<=n; i++)
10     b[i]=lower_bound(t+1,t+1+m,a[i])-t;
11 //a[i]为原来的数组,b[i]为离散化后的数组

我认为这个蛮明白得了,就显然过掉吧

优点——可处理重复元素只要一种的题目,时间复杂度肯定比map小

缺点——时间复杂度比第三种要高,且就本人刷的可怜的题量来说,实用度不如其他两种好

  • 结构体+重载运算符//cmp

这个对于我来说最不好说了,因为凡是用这个来处理的题,我都用map来搞-_-||

 1 struct A
 2 {
 3     int x, idx;
 4     bool operator < (const A &rhs) const
 5     {
 6         return x < rhs.x;
 7     }//也可以写个cmp函数排序
 8 };
 9 A a[MAXN];
10 int rank[MAXN];
11 int n;
12 scanf("%d",&n);
13 for(int i = 1; i <= n; ++i)
14 {
15     scanf("%d", &a[i].x);
16     a[i].idx = i;
17 }
18 //for(int i=1; i<=n; i++)
19 //    printf("%d  %d
",a[i].idx,a[i].x);
20 //printf("
");
21 sort(a + 1, a + n + 1);
22 //for(int i=1; i<=n; i++)
23 //    printf("%d  %d
",a[i].idx,a[i].x);
24 //printf("
");
25 for(int i = 1; i <= n; ++i)
26 {
27     rank[a[i].idx] = i;
28 //    printf("rank[%d] = %d
",a[i].idx,i);
29 }

X是原本的数字,idx是原本数字的位置,rank是离散化后的代号

(以下为原博内容,由于蒟蒻还不会(其实就是不想学),就直接贴上了

给你们个例子:
i      1 2 3 4
x     6 8 9 4
idx  1 2 3 4
排序后:

i      1 2 3 4  //离散化后的数字
x     4 6 8 9 
idx  4 1 2 3  //数字原来的所在的位置编号
将上面两行黑体数字对应起来 即是:rank[4]=1,rank[1]=2,rank[2]=3,rank[3]=4;  //rank[i]=j表示将原来在第i个位置上的数字离散化成j
so:
rank[1]=2;
rank[2]=3;
rank[3]=4;
rank[4]=1;
so:   6 8 9 4

就离散化为2,3,4,1
如果你想用原来的数字,就用排过序的结构体a[2]=6,a[3]=8,a[4]=9,a[1]=4; //a[i]=j表示排过序后现在的a数组里第i个数字的是j。j也就是第i小。
a[i]是原来的数字;
rank是离散化后的数字;

————————————————————————————后记————————————————————————————————

大概想说的,要说的,大概就是这么多。

欢迎大佬来指出错误或教我第三种是怎么搞的

原博客

至于相关题目先看这里,,,,,,,

 


















以上是关于随便说说——离散化的主要内容,如果未能解决你的问题,请参考以下文章

POJ 2528 Mayor&#39;s posters 离散化+线段树

POJ - 2528 线段树+离散化

渲染管道光栅阶段一“总览”

渲染管道光栅阶段一“总览”

随便说说Spring Data JPA(包含分页,复合查询)

离散化的思想和它的两种代码与区别