LCT学习笔记

虽说是学习笔记但却是复习笔记,这篇文章将会慢慢(因为我正在学)带大家学会LCT的各种用途,以下是我的复习/学习历程。

Step.0 熟悉模板

这是最重要的内容,(以后忘记了还要再来一遍)给大家几道题敲一敲,如果觉得LCT还背不熟一定要敲,不要嫌烦。

Luogu1501 SP9577

Step.1 LCT维护生成树

先来看一道题

考虑使用Kruskal的方法,将边按照边权从小到大加入生成树,如果联通则构成了一棵生成树。但是还要要求差值最小,也就是最小值最大,所以每次形成环的时候要在环上找到一个边权最小的边,然后把它断掉。

我们知道LCT可以非常方便地维护链上的信息,那么我们维护一条链的边权最小的边的编号就可以了。

如果已经做好Step.0的话相信代码不难写出。

然后就可以再看一道题了。

Step.2 LCT维护子树信息

我们知道LCT可以非常方便地维护链信息,却不能方便地维护子树信息,因为LCT与树链剖分一样,将整棵树剖成了一条一条的链(每条链是一棵Splay)。

于是我们注意到维护链信息其实就是把虚边忽略之后的子树,那么我们可以通过额外考虑虚子树的贡献来维护子树信息。

看一道题

我们需要维护的就是子树大小,因此需要记录一个$siz2[]$来额外记录虚子树的大小。

所以pushup的时候要改为

1 inline void pushup(int x){
2     siz[x] = 1 + siz2[x];
3     if(ch[x][0]) siz[x] += siz[ch[x][0]];
4     if(ch[x][1]) siz[x] += siz[ch[x][1]];
5 }

这样$siz[]$维护的就是整棵子树的大小,然后我们只用考虑哪些操作对虚子树大小产生了影响。

rotate和splay操作:没有改变边的虚实情况,所以没有影响

access操作:每次splay $x$到根后要改变$x$的右儿子,所以$siz2[x]$加上原来右儿子的大小减去新的右儿子的大小。

makeroot和findroot操作:没有直接改变边的虚实情况,所以不需考虑

cut操作:改变了子树大小,但每次cut之后需要pushup,所以不需考虑

link操作:将$x$向$y$连了一条虚边,因此需要将$siz2[y]$要加上$siz[x]$。

其他跟普通LCT没有任何区别,那也不贴代码了。

Step.# 离线维护图联通性

这是学习LCT的时候无意看见的,详见CF1140F

Step.3 LCT维护****

因为我鸽了,所以下次再见。

你可能感兴趣的:(LCT学习笔记)