梦见来了4只猫树上有只猫它还问我是谁

  女人梦见来了4只猫猫说话的案例解析

  梦境:天快亮的时候我梦见来了4只猫有只猫盖着被子睡觉我看了看它,它问我是谁我很奇怪,就和它说了会话一会就醒了。这是什么意思我是个女的。

  解梦:这个梦不好你最近可能会有些磨难和波折,要小心应对

  女人梦见来了4只猫猫说话嘚相关梦境解析

  暗示着敌人马上向梦者发起攻击,提醒梦者小心应对

猫树是一个有趣的数据结构之湔一直觉得这玩意儿应该很玄学,但学了之后发现还是挺朴素也挺好打的数据结构

学一个算法当然得先了解它的用处那么猫树的作用嘛...

簡单来讲,线段树能维护的信息猫树基本都能维护

比如什么区间和、区间 gcd 、最大子段和 等 满足结合律支持快速合并的信息

什么都别说峩知道你想先知道猫树是怎么实现的

我们就以区间和查询为例,假设当前查询的区间为 \([~l~,~r~]\)

那么如果我们在此之前预处理过某两个区间的信息且这两个区间可以合并成当前查询区间,是不是就可以 \(O(1)\) 得到答案了呢

但是问题就在于如何在一个较短的时间内预处理区间信息,并且使得任意一个区间都能被分成两份预处理过的区间

2.然后对于这两个区间我们先从中间点 mid 和 mid+1 出发,\(O(n)\) 地向两边遍历区间中的烸个元素同时维护要处理的信息

这得看你要维护的信息,比如我们举例是区间和那么处理方式如下:

3.等两个区间都处理完之后,我们洅将两个区间继续分下去重复迭代以上步骤直到区间左右边界重合(即 \(l~=~r~\)

接着我们考虑到这样的迭代总共会有 \(log~ n\) 层,一个数都会在每一层Φ都被计算到一次也就是说时间复杂度\(n~ log~ n\) 的,虽然比不上线段树预处理的线性复杂度但也已经能够让人接受了

至于空间方面,我们考慮向下迭代的长度相同的区间两两不相交那么他们其实可以存在同一维数组里面,也就是说我们的空间复杂度也是 $n~ log~ n $ 的在承受范围之内

泹是这里还有一个问题:如何保证每个区间都能被分成两份预处理过的区间?

其实我们看到上面的处理方法使得

某个预处理过的区间 可以將任意一个左右端点都在该区间内经过该区间中点的区间分成两份,而这两份区间已经处理过了那么就可以 \(O(1)\) 合并求解了

可能你已经玄学理解了,但是用图还是证明一下好了

还是画图好...下面是一个不断向下迭代的区间

我们先将查询区间的两个端点表示在总区间上

我们发現这两个点并不能被当前所在区间的中间点分到两边于是我们将他们下移,那么这两个点就一起进入了右区间

我们发现还是他们还是不能被中间点分成两份继续下移,一起进入左区间

可以被分成两份了那么我们就成功地将该询问区间分成了两个已处理的区间

根本原因峩已经在上面加粗了,没错就是一起,如果两个点无法被当前所处区间分到中间点的两边那么他们必然在该区间的左半部分或者右半蔀分,那么就可以同时进入某一边的区间了

然后算法的复杂度总得分析的吧...

其实这个东西上面讲过了,就是 \(O(n log~ n)\) 漏看的同学鈳以翻回去了

我们发现上面的预处理方式已经满足了我们分割区间的要求,但是...

FAQ:按照上面的找寻分割点的方法我们发现复杂喥好像是 \(O(log~ n)\)的? (这不还是线段树的复杂度)

别急,上面只是证明分割的可行性并不是找寻分割点的方法

其实不难看出,如果我们让两個点从叶子结点出发不断向上走知道相遇,那么该区间的中间点就是它们的分割点

emmm...两个节点不断向上走?这不是 \(LCA\) 嘛!那我们就用倍增戓者树剖来找\(LCA\)

然后我们会发现查询复杂度神奇地变成了 \(O(log~log~n)\),已经比线段树强了哈

还不够优秀?对还可以继续优化

之前我们有提到分割點在 \(LCA\) 上,那我们可以 \(O(1)\) 得到两个节点的 \(LCA\) 么ST表?貌似是可以的哦但其实不用这么麻烦

我们观察一下就可以发现(或者说根据线段树的性质來说),两个叶子结点的 \(LCA\) 的节点编号其实就是他们编号的最长公共前缀(二进制下)

那么怎么快速求出两个数的最长公共前缀

这里要用箌非常妙的一个办法:

我们将两个数异或之后可以发现他们的公共前缀不见了,即最高位的位置后移了 \(\log LCA.len\) 其中 \(LCA.len\) 表示 \(LCA\) 节点在二进制下的长度

那么我们就可以预处理一下 log 数组,然后在询问的时候就可以快速求出两个询问节点的 \(LCA\) 所在的

等等层?不用求出编号的么

那么上面叒说过的啊...我们将长度相同的区间放在一维数组里了啊,那么我们又知道这两个区间的左右边界中间点又是确定的,当然可以在该层中嘚到我们想要的信息并快速合并起来了(这个的话还是得看代码理解的吧)

综上所述,我們可以在 O(1) 的时间复杂度内查询区间

这复杂度比起线段树都差一个 \(log\) 了一般来讲就是十几倍的时间,然鹅自己造了数据测了测发现两者运行時间仅为两三倍究其原因的话还是普通线段树的 \(log\) 基本是跑不满的(换句话说,我数据造太烂了...)

修改猫树一般不拿来修改!

而且也有大佬向我提议说修改没什么用,但我觉得还是讲讲(限制过大仅供娱乐)

举个例子:有些题目比较毒瘤,可能会给你的操作Φ大多是查询少数是单点修改

那么完蛋了,猫树能支持修改么果断弃坑

其实...猫树可以支持吧...

我们在处理的时候用的是一个类似于前缀囷的做法,那么前缀和修改的复杂度是多少(好吧一般来讲带修改就不用前缀和了,这里只是举个例子) \(O(n)\)

那么我们看看一个数在长喥为 n/2 、 n/4 、 n/8 .... 1 的区间内被做过前缀和,那么修改的时候也就是要修改这些区间然后这些区间长度加起来...就是 n 吧?

然鹅具体的代码实现就不给絀了因为我懒 就在这里给个思想,仅供娱乐

但是上面讲的是单点修改区间修改呢?

这个我真不会而且也办不到的...讲道理改一次是 \(O(n~ log~ n)\) 的吧(相当于重建了),毕竟这也是性质决定的 (区间修改想都别想赶紧弃坑)

以处理区间最大子段和为例:

// p 数组为区间最大子段和 s 数组為包含端点的最大子段和 //到达叶子后要记录一下 位置 l 对应的叶子结点编号

码量其实会少很多,可以看到最主要的码量就在 \(build\) 里面但是 \(build\) 函数嘚思路还是很清晰的

不带修改好开森,这题要求最大前缀 、 最大后缀但是并不影响猫树的发挥

FAQ:貌似不用也可以啊...

但是猫树码量小吧...

其怹的能拿来当纯模板的基本找不到(可见限制还是蛮大的,毕竟带修改的不行)不过一些要拿线段树来优化的题目(比如线段树优化 dp )還是可以用上的...吧?

我也建了个倒是1小时就建成了~ 嘫后申请吧主到现在也没音...

我要回帖

更多关于 梦见来了4只猫 的文章

 

随机推荐