【口胡记录——准备NOIP2018考完然后考完期末考试再来实现】一种在线区间众数O(log^2n)维护做法

注:本blog纯属蒟蒻的原创做法,若有不对的地方,请指出,并尽情地喷.

众所周知,可以离线的区间众数做法很多,但问起在线做法,很多人就只会一种分块了.

我突发奇想花了一个下午的时间不断思考该怎么在线区间众数,最后想出了一种貌似可行的办法.

首先我的算法思路大体是从线段树合并开始的,那个时候我独自想出了如何求出一棵树上所有节点的子树众数的做法.

我的做法首先是按照线段树合并的套路,每个节点建立一棵权值线段树,然后每个节点存储出现次数最多的权值数量,然后不断的向上合并,就可以完美解决这个问题.

之后我想既然权值线段树可以解决众数问题,那么我们是不是可以写主席树来解决这个问题呢.

最后思考了一下,不行,不满足区间减法性质,没办法实现树状数组套主席树.

那线段树呢?可以是可以,但是主席树合并的速度就不得而知了,而且这种做法的空间有大概率吃不消,而且常树也不小.

但是我却想到了一种可以直接处理这类问题的一个不带修改的做法,不过我们得让查询区间不重合.

我们这次依然使用线段树合并,每个元素建立一棵权值线段树,然后把每个区间的答案都直接合并出来,由于区间不重,所以我们合并之后就不用再拆开来.

然而仔细一想后发现,这对于在线区间众数并没有什么帮助.

不过上面那个主席树合并的思想倒不错,现在我们可以把主席树换掉,换成一种可快速合并的平衡树(splay,fhq treap或者leafy tree).

我们现在储存的这棵平衡树就是一棵可重的权值平衡树了,其实我的方法类似于二逼平衡树.

那么我们就可以查询的时候直接合并上去,修改的时候直接把一个点改掉,然后不断向上合并,两个操作的时间复杂度均为\small O(log^2n),但是常数大的惊人,以splay和fhq treap的惊人常数来看,这种做法的时间复杂度可能还是分块好,毕竟这两棵平衡树的常数套上线段树的常数之后一般都会远超一个log甚至两个log.

所以我们选用leafy tree(在下在这里开始奶leafy tree了!虽然我不会,但毕竟只是口胡),在2018年的国家集训队论文中有对这个的详细介绍,据说常数巨小,且功能广泛.

论文名(网上没有下载地址):《Leafy Tree 及其实现的加权平衡树》----成都市第七中学 王思齐.

不过我们再拓展一下,维护单点插入怎么办?

答曰:由于线段树其实也是一种leafy tree,我们直接把线段树改成leafy tree...

猜你喜欢

转载自blog.csdn.net/hzk_cpp/article/details/81393921
今日推荐