Link-Cut-Tree(动态树 LCT)


1.定义

1. 偏爱子节点: 一颗子树内最后访问的点若在该子树根节点 X 的某个儿子节点 P 的子树中,则称 P 为 X 的偏爱子节点。

2. 偏爱边:连向偏爱子节点的边。

3. 偏爱路径:一条全为偏爱边构成的路径(一定是一条链,类似于树链剖分的重链)

4. 每一条偏爱路径(以下直接写做重链)都由一棵Splay来进行维护.

注意:

  1. LCT不一定是二叉树。
  2. 若 p->fa==NULL 则p为其所在 LCT 的树根

    3. Splay -> 路径(且一定是树上的一条链)

    4. LCT -> 一棵树(由多棵Splay构成的森林)

    5. 整张图 -> 多棵 LCT 构成的森林(好几片Splay构成的森林)

    6. Splay作为辅助树,改变的只是 LCT 中的轻重边关系

    7. 基本的结构体变量
struct node{
node* fa;node* son[2];
bool rev,is_root;//区间反转标记和是否是Splay的根
}

2.基本操作

代码均使用指针。

可自己画图以理解。

注:以下代码中有:

#define __ NULL
#define ls son[0]
#define rs son[1]
#define get_son(a) (a->fa->rs==a)
  1. Splay的操作(为了适应LCT有些改动)
void rotate(node* p)
{
if(p->is_root) return;
register node* q=p->fa;register node* gp=q->fa;
register int k=get_son(p);
q->son[k]=p->son[k^1];
if(p->son[k^1]!=__) p->son[k^1]->fa=q;
p->fa=gp;
if(q->is_root) q->is_root=0,p->is_root=1;
//由于不能影响到另一棵Splay,要用 is_root 判断
else if(gp!=__) gp->son[get_son(q)]=p;
q->fa=p;p->son[k^1]=q;//记住旋转时指针指向的变更顺序!!
return;
}
void Splay(node* p)
{
if(p==__) return;
push(p);//在Splay到根之前要先下传标记(区间反转)
while(!p->is_root){//别旋出去啦!
if(p->fa->is_root) {rotate(p);break;}
if(get_son(p)==get_son(p->fa)) rotate(p->fa);
else rotate(p);rotate(p);
}
return ;
}

2.\(access(p)\) 访问某节点

void access(node* p)//访问某节点 p ,单独开辟一条路到节点 p ;
{
register node* pre=__;
while(p!=__){
Splay(p);
if(p->rs!=__) p->rs->is_root=1;
p->rs=pre;//切断右子树(不同Splay的父亲记录只从子到父)
if(pre!=__) pre->is_root=0;
//pre一定是上一棵Splay的根,要把它加到另一棵Splay中;
//updata(p);(更新)
pre=p;p=p->fa;
}
}

3.\(makeroot(p)\) 使p变为其所在LCT的根节点

void m_root(node* p)//使某个点成为根
{
if(p==__) return;
access(p);Splay(p);//连一条从树根到 p 的路径
p->rev^=1;
/*
因为树根的深度应要是最小的,上面操作只是让 p 成为了原树根所在Splay的根,
但他仅有左子树,深度最大,故还应该反转该Splay,使得 p 成为真正的根
(即保证深度为整棵LCT中深度最小的点); 上述操作并不会改变原树的结构
*/
}

4.\(Link(u,v)\) 连接u,v所在的LCT,使之变为一棵LCT

void Link(node* p,node* q)
{
m_root(p);//不改变p所在树的结构,只是将p提取出来便于操作
p->fa=q;//连接了两棵LCT改变了原图的结构(连的边是轻边,不用updata)
}

5.\(split(u,v)\) 分离出u->v这条路径,其上的点都在一颗Splay中,可迅速获得路径上的信息

void split(node* p,node* q){
m_ root(p);
access(q);
Splay(q);
}

6.\(Cut(u,v)\)砍断边\((u,v)\)分成两棵LCT

void Cut(node* p,node* q)
{
split(p,q);
if(q->ls==p) p->fa=q->ls=__,p->is_root=1;
//此时q所在Splay仅有他一个节点
}

6.标记的下放

void push_down(node* p)
{
if(p==__||p->rev==0) return;
p->rev=0;
if(p->ls!=__) p->ls->rev^=1;if(p->rs!=__) p->rs->rev^=1;
swap(p->ls,p->rs);
}
void push(node* p){//数据不大时可写成递归版本
h=1;st[h]=p;
while(!p->is_root) st[++h]=(p=p->fa);
for(int i=h;i;i--) push_down(st[i]);
}
void push(node* p)//递归版本
{
if(p==__) return;
if(p->is_root==0) push(p->fa);
push_down(p);
}

7.\(find(p)\) 返回p所在LCT的根节点(通常用于判断两点是否联通)

node* find(node* p)
{
for(access(p),Splay(p);p->ls!=__;p=p->ls);
return p;
}

3.LCT的应用

LCT可以很方便的提取出两点之间的路径和改变原树的形态,因此在处理一些树上的路径问题非常行之有效。

1.动态询问两点之间的连通性

例题.LuoguP2147 [SDOI2008]Cave 洞穴勘测 用find操作即可

2.动态询问树上两点间的距离

例题1.BZOJ2002: [Hnoi2010]Bounce 弹飞绵羊

题解

例题2.LuoguP3721 [AH2017/HNOI2017]单旋

题解

3.各种树上路径问题

例题1.BZOJ3669: [Noi2014]魔法森林 动态维护最小生成树

题解

持续更新...

动态树(Link-Cut-Tree)简单总结(指针版本)的更多相关文章

  1. 动态树(Link Cut Tree) :SPOJ 375 Query on a tree

    QTREE - Query on a tree #number-theory You are given a tree (an acyclic undirected connected graph) ...

  2. LCT总结——概念篇+洛谷P3690[模板]Link Cut Tree(动态树)(LCT,Splay)

    为了优化体验(其实是强迫症),蒟蒻把总结拆成了两篇,方便不同学习阶段的Dalao们切换. LCT总结--应用篇戳这里 概念.性质简述 首先介绍一下链剖分的概念(感谢laofu的讲课) 链剖分,是指一类 ...

  3. P3690 【模板】Link Cut Tree (动态树)

    P3690 [模板]Link Cut Tree (动态树) 认父不认子的lct 注意:不 要 把 $fa[x]$和$nrt(x)$ 混 在 一 起 ! #include<cstdio> v ...

  4. 【刷题】洛谷 P3690 【模板】Link Cut Tree (动态树)

    题目背景 动态树 题目描述 给定n个点以及每个点的权值,要你处理接下来的m个操作.操作有4种.操作从0到3编号.点从1到n编号. 0:后接两个整数(x,y),代表询问从x到y的路径上的点的权值的xor ...

  5. LuoguP3690 【模板】Link Cut Tree (动态树) LCT模板

    P3690 [模板]Link Cut Tree (动态树) 题目背景 动态树 题目描述 给定n个点以及每个点的权值,要你处理接下来的m个操作.操作有4种.操作从0到3编号.点从1到n编号. 0:后接两 ...

  6. LG3690 【模板】Link Cut Tree (动态树)

    题意 给定n个点以及每个点的权值,要你处理接下来的m个操作.操作有4种.操作从0到3编号.点从1到n编号. 0:后接两个整数(x,y),代表询问从x到y的路径上的点的权值的xor和.保证x到y是联通的 ...

  7. link cut tree 入门

    鉴于最近写bzoj还有51nod都出现写不动的现象,决定学习一波厉害的算法/数据结构. link cut tree:研究popoqqq那个神ppt. bzoj1036:维护access操作就可以了. ...

  8. Link Cut Tree学习笔记

    从这里开始 动态树问题和Link Cut Tree 一些定义 access操作 换根操作 link和cut操作 时间复杂度证明 Link Cut Tree维护链上信息 Link Cut Tree维护子 ...

  9. [BJOI2014]大融合(Link Cut Tree)

    [BJOI2014]大融合(Link Cut Tree) 题面 给出一棵树,动态加边,动态查询通过每条边的简单路径数量. 分析 通过每条边的简单路径数量显然等于边两侧节点x,y子树大小的乘积. 我们知 ...

  10. 学习笔记:Link Cut Tree

    模板题 原理 类似树链剖分对重儿子/长儿子剖分,Link Cut Tree 也做的是类似的链剖分. 每个节点选出 \(0 / 1\) 个儿子作为实儿子,剩下是虚儿子.对应的边是实边/虚边,虚实时可以进 ...

随机推荐

  1. Linux监控命令之==>netstat

    一.命令说明 netstat 命令用于显示本机网络连接.运行端口.路由表等信息 二.参数说明 -a (all):显示一个所有的有效连接信息列表,包括已建立的连接(ESTABLISHED),也包括监听连 ...

  2. 实现Servlet接口

    1 右键项目->Build Path->Configure Build Path 2 Add Library...->Server Runtime 3 Apache Tomcat-& ...

  3. Several ports (8005, 8080, 8009) required by Tomcat v8.5 Server at localhost are already in use.

    Several ports (8005, 8080, 8009) required by Tomcat v8.5 Server at localhost are already in use. The ...

  4. Vmware centos 虚拟机 磁盘扩容

    一,lvm ext4 扩容 1,首先关闭虚拟机,在vSphere Client 将硬盘大小增加或者新增一块硬盘 (从原来10G增加到50G) 2,开机 此时,df -hT只显示原来的磁盘大小 使用 f ...

  5. python__005

    一.字符串格式化 #字符串的拼接#msg='i am a best boy'+'非常帅'print(msg)name=input('name:')hobby=input(('hobby:'))age= ...

  6. cocos2dx基础篇(4) 标签CCLabel

    [本节内容] cocos2dx三种文字字体的显示:CCLabelTTF(一般字体).CCLabelAtlas(自定义字体).CCLabelBMFont(自定义字体) CCLabelTTF CCLabe ...

  7. LeetCode.941-有效山形数组(Valid Mountain Array)

    这是悦乐书的第360次更新,第387篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第222题(顺位题号是941).给定一个整数数组A,当且仅当它是一个有效的山形数组时返回 ...

  8. Logistic回归实战篇之预测病马死亡率

    利用sklearn.linear_model.LogisticRegression训练和测试算法. 示例代码: import numpy as np import matplotlib.pyplot ...

  9. 解决ajax跨越问题

    解决方案: ajax跨域访问是一个老问题了,解决方法很多,比较常用的是JSONP方法,JSONP方法是一种非官方方法,而且这种方法只支持GET方式,不如POST方式安全.   如果跨域使用POST方式 ...

  10. Hive-Container killed by YARN for exceeding memory limits. 9.2 GB of 9 GB physical memory used. Consider boosting spark.yarn.executor.memoryOverhead.

    Caused by: org.apache.spark.SparkException: Job aborted due to stage failure: Task times, most recen ...