前言:
在恶心了几道LCT算法的题后,勉强领悟到一点LCT的用处
作为一个比较经典的数据结构,LCT的应用范围比较广泛,比如动态维护最小生成树,动态维护双联通分量,以及其它的一些动态路径询问的问题。尽管在子树问题上,LCT算法显得有些无力(出门左转找ET),但毕竟很多子树问题可以用DFN+Splay水过,但路径询问,却几乎找不到可以替代LCT的算法。
基本概念:
LCT算法,其实就本质而言,是一个十分暴力却优美的算法。优美在于,它基于一个神奇的树上算法:树链剖分。暴力在于,它的实现过程异常简单,只是用Access与Splay两个函数,就可以完成几乎所有操作。
树链剖分是LCT的理论基础,常规的树链剖分可以在 O(Nlog2N) O ( N l o g 2 N ) 复杂度内处理大多数路径、子树问题(但有时离线的点分治却能比它更优秀)。
树链剖分是预处理出来的,也就是说它不能支持对树的结构有修改的问题。而LCT就是用于解决这一漏洞的。
由于树的形态有变化,所以重边和轻边的关系要动态存储,在每一条重链上,都用一个Splay平衡树来维护这条链上的信息,而Access操作,是将该点与根的连线变为一条重链。具体的原理与时间复杂度的证明,这里不再赘述。
典型建模与应用:
首先,最常见也最简单的应用,是直接用懒标记来存储一些需要的信息。当然,有的这类题也可以把人恶心出病来,但绝大多数这类题目都属于不用太多思考就能过的。比如模板题Qtree系列,基本上都是这类题。
有点难度的,比如BZOJ3091城市旅行,
这道题需要4个懒标记互相配合修改:(以下有剧透成分)
由于题目要记录“路径任意选择两个点的期望”,所以很显然要统计所有方案总数,于是一个懒标记存储 n∗1∗a