说好的专题。。。
lct的一些概念看论文 杨哲《QTREE解法的一些研究》 简单易懂。
首先不要把lct想象得很难,其实很水的。lct就是很多splay树维护的树。。。
lct的access操作就是在原树中拓展一条点到根的类二叉树出来(用splay来维护)
这里,splay树是按深度作为关键字的,当然,在无向图中(无环)可以任意指定一个点为根,这点要切记(因为在这里操作时,有些操作需要换根,所以一定要理解)
link操作就是将点作为这颗类二叉树的根,然后合并
cut操作就是将点作为这颗二叉树的根,然后在拓展一条另一个点的splay路径(此时这两个点一定要有边连接,这样使得拓展上来的根一定在另一个点拓展上来的splay树的左子树上,因为他们有边连接),将左子树的父亲设为0,并且去掉左子树
getroot操作就是将点拓展了splay后,并且将它伸展到根,此时,最小的子树(深度最浅,即最左的子树)就是这颗splay的根
makeroot操作就是将点拓展为现在所在的树的根,即换根,伸展到根后只需要将左右子树反向,就是将深度换了(根据splay有良好的下放操作,我们将翻转用标记来翻转,使得时间复杂度减小)
split操作就是将两个点的路径拓展出来进行操作,即makroot(x); access(y); splay(y);
额,我自己都觉得说得不好 。。囧
说些注意的地方吧:
- 在维护splay树时,当x为这棵树的根时,并不意味着它没有父亲,只是他的父亲没有这个孩子(这点一定要理解!!),因为我们维护的是一棵多叉树,但是我们拓展的是二叉树,所以,你懂的。怎么修改呢,在原来splay操作的判null的地方都用现在的特判。
- 在旋转时,还需要判断父亲的父亲是否为上边所说的那样,如果是,就不要更新他,因为这两个点不在一颗splay上。
- splay操作时,下放标记我们要用一个栈到达他的根往下放标记。(因为每个点进行操作时,祖先的tag必须已经全部下放过。而lct是多颗splay树,是按深度排序的,会导致splay的节点祖先都还没有下放过标记。)
- 每一次更新节点操作,都要splay至树根再操作,理由和上边差不多。因为可能在询问路径时,之前更新过的节点是在那棵splay树的靠右的地方,导致在原树中浅的节点没有得到更新。(不懂请q我或看例题5)
- 不要把splay和原树搞混。
- 不要认为只有一颗splay树。
- 不要认为理所当然,,,在思考的时候好好思考。
好了,我认为差不多了。。
一些题我之前也发了博文,我现在再放出来。。
例题: