学习LCT小结
前前言
话说前面部分大概是我一年前搞的吧。
最近又复习了一哈LCT,那就补补坑吧。
注意,为了区分,从我写spaly开始都是现在写的。
前言
首先,LCT是什么呢?
我们看看百度百科——
LCT即自动细胞学检测系统,又称液基细胞学检测系统。是宫颈筛查的一种方法。
疏松结缔组织(loose connective tissue)又称蜂窝组织(areolar tissue),其特点是细胞种类较多,纤维较少,排列稀疏。疏松结缔组织在体内广泛分布,位于器官之间、组织之间以至细胞之间,起连接、支持、营养、防御、保护和创伤修复等功能。
好吧,不是这个。
LCT即为link-cut-tree
是一种解决动态树的有效利器。
动态树是一类问题,常见的有维护树的连通性,求树上路径的极值等。
然后LCT即为一种用Splay来维护树链剖分的算法,简单理解为“支持删边、加边的动态树链剖分”
前置技能:
树链剖分https://blog.csdn.net/HiChocolate/article/details/77170675
(不会的可以看看我写的)
Splay https://blog.csdn.net/qq_30974369/article/details/77587168
(不会的可以看看不是我写的)
重点是树链剖分的全部内容加上splay的一些基本操作(如标记下传、区间翻转《排序机械臂》)
一些定义
既然百度百科没有很好的定义来学习,那我就来大致讲讲。(实际上是我懒得打定义)
LCT的本质也是树链剖分,它的树也是用很多的偏爱路径和非偏爱路径来连接起来的。
这些为了方便理解,不妨也用树链剖分的定义来定义。
1、重边连起来会组成重链,重链之间没有公共点。
我们首先跑一遍算出dfn序之后,我们就可以找到很多很多条重链。
2、那么对于一颗树,其中一条重链的点,都在一颗splay中,关键字是深度。
3、树链剖分的重链是一成不变的,但是LCT的重链是可以随意改变的。这也注定了LCT的重链需要用到splay来维护。
4、重链与重链之间的边在splay中用虚边来表示。
5、一条重链的虚边会存在它的splay的根上,指向这条重链的顶点的father所在的重链的splay的根。
就是这么多啦。
其实这样子很难理解4与5的定义什么意思,那么我们画画图。
上面加粗的边即为重边,然后连成重链。
然后,我们把每一条重链都给弄出来,对它建一颗splay,那么就变成——
那么对于上面的这个图,三角形就代表一个splay,每个splay对应着LCT上的每个链。
那么有些链是用一条轻边连起来的,那么在splay上就用一个虚边连接。
理解定义5,就会发现在这张图上,这些有向边可以表示为虚边。
然后就大致介绍完LCT的基本定义与构造了。
一些干货
由于我们的这个LCT并不需要把它建出来,只需要维护spaly即可。
因此,我们节点维护下面的一些基本值:
- fa表示当前节点spaly上的父亲
- pf表示当前节点在LCT上虚边连接的点
- son[1/0]在spaly上的儿子
关于spaly
其实spaly在LCT中只需要利用其旋转,就可以基本完成一切操作(废话)
那么在旋转过程中,需要改进的只有一个向虚边传送。
代码
void rotate(int x)
{
int y=t[x].fa,k=get(x);
if(t[y].fa) t[t[y].fa].son[get(y)]=x;
if(t[x].son[!k]) t[t[x].son[!k]].fa=y;
t[y].son[k]=t[x].son[!k],t[x].fa=t[y].fa,t[y].fa=x,t[x].son[!k]=y;
update(y),update(x);
t[x].pf=t[y].pf;//就在这里!!!
}
核心操作access
我们定义一个操作\(access(x)\)表示把当前x到根的所有边都变成重边,然后把这条链以外的所以边变成轻边。
具体操作看图:
(盗盗图)
应该很好理解。
代码:
void access(int x)
{
for (int y=0;x;update(x),y=x,x=t[x].pf)//一直跳重链
{
splay(x,0);
t[t[x].son[1]].fa=0;//断掉原来的重链
t[t[x].son[1]].pf=x;
t[x].son[1]=y;//把下面的spaly接到上面
t[y].fa=x;
t[y].pf=0;
}
}
基本操作1 makeroot
我们定义一个操作\(makeroots(x)\)表示把x变成LCT的根。
操作简单,先access一下,那么我们就可以得到一颗spaly。
然鹅这颗spaly最右边的点是x,我们要把他变成最左边。
于是把它旋转到根,翻转一下即可(翻转就是排序机械臂中的翻转)
代码:
void make(int x)
{
swap(t[x].son[0],t[x].son[1]);
t[x].tag^=1;
}
void makeroot(int x)
{
access(x),splay(x,0);
make(x);
}
基本操作2 findroot
我们定义一个操作\(findroots(x)\)表示寻找x所在树的root。
这个操作有什么用呢?
你可以用这个代替并查集,只是时间多了些
用醋很多,就不一一介绍了。
如何实现?
access(x)一下,然后我们发现x和原本的根在同一spaly上。
然后询问spaly上最左边的点即可。
int findroot(int x)
{
access(x),splay(x,0);
for (;t[x].son[0];x=t[x].son[0]);
return x;
}
基本操作3 link
这个就很帅气了。
我们定义一个操作\(link(x,y)\)表示连接x和y这条边。
方法很简单,我们先makeroot(x),然后把x连接到y即可。
void link(int x,int y)
{
makeroot(x);
if(findroot(y)!=x) t[x].pf=y;
}
基本操作4 cut
我们定义一个操作\(cut(x,y)\)表示删掉x和y这条边。
我们考虑makeroot(x),然后access(y)。
如果x和y之间有连边,那么y必定是x的儿子。
断掉即可。
void cut(int x,int y)
{
makeroot(x),access(y),splay(y,0);
if(t[x].fa==y) t[y].son[get(x)]=t[x].fa=t[x].pf=0;
}
应用
大致就是上面的这些操作。
例题?洛谷上很多。
当然,https://blog.csdn.net/HiChocolate/article/details/101380259
这也是一个模板。
原文地址:https://www.cnblogs.com/RainbowCrown/p/11600799.html
- 常用SQL语句和语法汇总
- Python学习笔记1——斐波那契数列
- 视觉传感器几大技术要点详解!
- Spark之搜狗日志查询实战
- 区块链与数字货币是什么关系呢?
- 保存数据到MySql数据库——我用scrapy写爬虫(二)
- 人工智能将取代人类?危机亦或是新的机遇
- 大数据驱动的未来网络:体系架构与应用场景(下)网络架构与场景详解
- 冷静点,NVIDIA 禁止 Geforce 进数据中心想限制的并不是深度学习
- 智能机器人崛起背后的中国力量
- 企业微服务架构转型-实施步骤
- Andrew Ng机器学习课程笔记--week2(多元线性回归&正规公式)
- 科技第六感:黑客控制你的车!不信?其实很简单
- python多版本的pip共存问题解决办法
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Javascript之其实我觉得原型链没有难的那么夸张!
- 归纳一下:C#线程同步的几种方法
- C# 主界面的扁平化
- C# LINQ
- Oracle基本参数(DB_NAME)
- Oracle基本参数(DB_RECOVERY_FILE_DEST,DB_RECOVERY_FILE_DEST_SIZE)
- Oracle基本参数(DB_UNIQUE_NAME)
- Oracle基本参数(DB_DOMAIN)
- Oracle基本参数(INSTANCE_NUMBER)
- Oracle基本参数(LDAP_DIRECTORY_SYSAUTH)
- C#调用C++编写的DLL
- Oracle基本参数(LOG_ARCHIVE_DEST_n)
- [安装文档]Oracle 12c 单节点安装之安装前准备
- Oracle基本参数(NLS_LANGUAGE)
- Oracle基本参数(NLS_TERRITORY)