本篇博客仅为个人思考,可能全是错的地方。大佬勿喷,在评论区指出即可。
while(1)我是个菜鸡。
2019CSP,day1T3 我在考试的时候面对点的编号和点上的数值,本来就是树形结构,还要交换。
于是我看了一个小时(划重点 一个小时的痛)然后我没了(抱头痛哭)
痛定思痛,据说离散化和下标啥的有关,于是写了一篇博客,大佬勿喷(蒟蒻的我瑟瑟发抖)
离散化是程序设计中一个常用的技巧,它可以有效的降低时间复杂度。其基本思想就是在众多可能的情况中,只考虑需要用的值。离散化可以改进一个低效的算法,甚至实现根本不可能实现的算法。要掌握这个思想,必须从大量的题目中理解此方法的特点。例如,在建造线段树空间不够的情况下,可以考虑离散化。
设有4个数:1234567、123456789、12345678、123456排序:123456<1234567<12345678<123456789 => 1<2<3<4那么这4个数可以表示成:2、4、3、1 --------------摘自令人看不懂的度娘
我的理解就是,把很大的数,由于题目不需要用到它的数值,只需要用到相对大小甚至与它的存在与否(hash也行,还简单),我们就可以用离散化。
它实际上就是用每个数是第几大用来代替这个数。
#define 大 小
拿上面的例子来说 1234567、123456789、12345678、123456
我们首先需要每个数是第几大的,那么sort然后再去重!
当当当当 123456<1234567<12345678<123456789
那么123456是第一大 就是1,1234567是第二大 就是2 以此类推
然后怎么做??
我当年接触的做法好像是按原来下标再给排回去(开个结构体,存个数值和下标以及rank)然后O(1)查询
好像可以哦,离散化的问题就这么被解决了?(挠头)
当然 正常的做法是再开一个c数组,对于原来的一堆数(假设是数组a),从前往后依次二分它在排序后的数组(假设是b)中的下标,然后这个下标就是它是第几大的,就用这个数字来代替这个huge的数,最后O(logn)查询?
好像就这样??
还有调用,比如要统计每个数出现次数,每个数用大小代替,然后num[rank]++; 最后再枚举每个数,找num[rank]。
举个例题cinema。
考虑一下数字在1-n??
然后仍然用第几大代替,举个例子 2,4,3,1
那么排序 4,3,2,1
怎么求出4所在原来的下标??已知a[2]=4 怎么找出这个2??
如果直接用num[4]就好了。
啊我蠢了,直接cin>>a[i];num[a[i]]=i;
最后说一下我CSP的暴力做法,不是要求交换数字,按数字的顺序将其节点编号依次排列然后字典序最小吗(我又晕了)
那么1能在1号节点就一定要在1号节点,同时还要考虑让其他数字也尽可能的在较小的节点。
不是有链和菊花图吗,菊花图的交换是很容易发现每个点(根除外)只能换一次,而链意味着要让1放到1号点,必定直接一路交换过去
然后对于链,找出1在哪号点,然后一直往前换,然后找2号点有没有被换过,以此类推
然后对于树,大概要分奇偶,但n肯定是160,所以最后根节点会在某个子节点上,同理从1开始考虑就行了
原来得出某个数的下标和离散化并没有关系?那么我这么多天都在干啥。
离散化为啥不用hash。。。emm
好吧,或许人生就是这样,或许最终的终点并不像自己想像的那样,但过程很美好。