学习笔记::lct
我已经忘了lct
1.lct能干什么
能维护一个序列,能做线段树做的事
能维护一颗静态的树,能做树链剖分和线段树做的事
能维护一个动态的序列,能做splay做的事
能维护一颗动态的树,能做splay和树链剖分的事
所以lct=splay+树链剖分
2.怎么维护
树链剖分是利用轻重链剖分的性质
那么lct也要维护轻重链,只不过由于有加边和删边所以随时在变化
lct是由若干颗splay组成的,每颗splay代表了一条重链,splay的关键字是深度
在树链剖分里,每次是对一条重链进行操作,然后爬到链顶的父亲进入下一条重链
所以每一颗splay的根节点的父亲就是下一条重链的某个位置
这里splay的父亲和孩子是不对应的,也就是说b是a的父亲,但a不一定是b的孩子
孩子对应的是重链,父亲对应的是轻链
3.操作
所有的link cut都是基于access这一个操作
access(x)操作是指将x到根的链变为重链,并且x为最深的点
怎么实现?因为现在x到根的路径是由很多条重链组成的,现在我们要将这些重链重构变成一条重链
考虑暴力,我们先爬到上一条重链,这个过程是先把x splay到根,那么x的父亲就是上一条重链中的某个位置y,那么我们要把y之后的重链换为x
由于splay维护的是深度,那么x自然是比上一条重链中所有点都要深的,所以我们把ch[y][1]=x,fa[x]=y,相当于强制切换了重链
重复这个过程直到到达根
这个复杂度均摊是log的
然后一系列操作由此衍生
换根:先access(x),将路径提取出来,那么这棵splay里就是x->root构成的重链,然后splay(x),由于x是最深的,那么ch[x][0]=0,所以这个时候我们对换左右儿子就相当于把x的深度变成最浅的了,也就实现了换根
也就是access(x) splay(x) paint(x)
link(x,y):x连到y下面,那么把x当成y的轻儿子,直接rever(x),fa[x]=y
cut(x,y):提取出(x,y)的路径,rever(x),access(y) splay(y),那么x->y的路径就到了一颗splay里,由于x和y相连,并且x现在比y浅,那么x肯定在y的左儿子,直接ch[y][0]=0 fa[x]=0,并且upd(y)
单点加:直接加到对应的点上然后splay一下就行了,lct中编号对应的是原树的编号
区间加:提取出路径,然后就打个标记