Last updated on June 18, 2024 pm
前言
好了,晚自习要回来机房了。既然回都回了,那就好好复习把。
正文
作用
首先要搞清楚LCT可以干什么。简单来说,LCT可以维护一颗树上的链的信息,比如最大值,最小值,和与积等等(满足结合律的应该都可以)。、 然后,它还可以进行删边,加边和更改节点信息等操作。 这就是机草了 :smile:
操作
首先是初始状态。初始状态就是每一个节点都是一条实链,然后每条树边都是一条虚链。
access(x)
这个操作是把根节点和x节点放在同一个splay当中:
1 2 3 4
| inline void access(int x){ for(int y=0;x;y=x,x=f[x]) splay(x),c[x][1]=y,pushup(x); }
|
splay(x)
这个操作就是把节点x转到x所在的splay的根的位置上:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| void rotate(int x) { int y=fa[x]; int z=fa[y]; int k=ch[y][1]==x; int w=ch[x][1-k]; if (noroot(y)) { ch[z][ch[z][1]==y]=x; } ch[x][1-k]=y; ch[y][k]=w; if (w) fa[w]=y; fa[x]=z; fa[y]=x; pushup(y); } void splay(int x) { int y=x; int z=0; st[++z]=y; while (noroot(y)) { st[++z]=fa[y]; y=fa[y]; } while (z) pushdown(st[z--]); while (noroot(x)) { y=fa[x]; z=fa[y]; if (noroot(y)) { rotate((ch[y][0]==x)^(ch[z][0]==y)?x:y); } rotate(x); } pushup(x); }
|
makeroot(x)
这个函数可以将节点x变成LCT的根。
1 2 3 4 5 6 7 8
| inline void pushr(int x){ swap(c[x][0],c[x][1]); r[x]^=1; } inline void makeroot(int x){ access(x);splay(x); pushr(x); }
|
Q:为什么pushr可以将splay整个反过来? A:
每一个Splay维护的是一条从上到下按在原树中深度严格递增的路径,且中序遍历Splay得到的每个点的深度序列严格递增。
return;
其实理解了上面这一些东西就差不多全部懂了,剩下的来看这篇把: LCT总结——概念篇+洛谷P3690 Link Cut Tree(动态树)(LCT,Splay) 终 :smile: