动态树是个好玩的东西

LCT题集

预备知识

Splay

树链剖分(好像关系并不大)

动态树(Link-cut tree)

先搬dalao博客

  • 什么是LCT?

    动态树是一类要求维护森林的连通性的题的总称,这类问题要求维护某个点到根的某些数据,支持树的切分,合并,以及对子树的某些操作。其中解决这一问题的某些简化版(不包括对子树的操作)的基础数据结构就是LCT(link-cut tree)。

    LCT的大体思想类似于树链剖分中的轻重链剖分,轻重链剖分是处理出重链来,由于重链的定义和树链剖分是处理静态树所限,重链不会变化,变化的只是重链上的边或点的权值,由于这个性质,我们用线段树来维护树链剖分中的重链,但是LCT解决的是动态树问题(包含静态树),所以需要用更灵活的Splay来维护这里的“重链”

讲了这么多,其实就是维护森林的树链剖分,每一条链用Splay维护

LCT的主要性质

  1. 每一个Splay维护的是一条从上到下按在原树中深度严格递增的路径,且中序遍历Splay得到的每个点的深度序列严格递增。

    比如有一棵树,根节点为1(深度1),有两个儿子2,3(深度2),那么Splay有3种构成方式:

    {1−2},{3}

    {1−3},{2}

    {1},{2},{3}(每个集合表示一个Splay)

    而不能把1,2,3同放在一个Splay中(存在深度相同的点)

  2. 每个节点包含且仅包含于一个Splay中

  3. 边分为实边和虚边,实边包含在Splay中,而虚边总是由一棵Splay指向另一个节点(指向该Splay中中序遍历最靠前的点在原树中的父亲)。

    因为性质2,当某点在原树中有多个儿子时,只能向其中一个儿子拉一条实链(只认一个儿子),而其它儿子是不能在这个Splay中的。

    那么为了保持树的形状,我们要让到其它儿子的边变为虚边,由对应儿子所属的Splay的根节点的父亲指向该点,而从该点并不能直接访问该儿子(认父不认子)。

各种操作

access(x)

打通\(x\)到动态树的根的路径(使路径上的所有点在同一个Splay中)

void access(int x) {
for (int y = 0; x; y = x, x = t[x].fa)
splay(x), t[x].ch[1] = y, pushup(x);
return ;
}

makeroot(x)

使\(x\)变成动态树的根

void makeroot(int x) {
access(x); splay(x);putrev(x);
return ;
}

findroot(x)

用来判断连通性(类似并查集)(findroot(x)==findroot(y)表明x,y在同一棵树中)

inline int findroot(int x) {
access(x); splay(x);
while (t[x].ch[0]) pushdown(x), x = t[x].ch[0];
return x;
}

split(x,y)

打通\(x\)到\(y\)的路径(类似access)

void split(int x, int y) {
makeroot(x), access(y), splay(y);
return ;
}

link(x,y)

连接\(x-y\)

void link(int x, int y) {
makeroot(x);
if (findroot(y) == x) return ;//已经连通
t[x].fa = y;//如果写成t[y].fa = x, y与原先的树就断开,就不会与其连通
return ;
}

cut(x, y)

断开\(x-y\)

void cut(int x, int y) {
makeroot(x);
if (findroot(y) == x && t[x].fa == y && !t[x].ch[1])//满足它们直接连接才断开
t[x].fa = t[y].ch[0] = 0, pushup(y);
return ;
}

例题

洛谷P3690 【模板】Link Cut Tree (动态树)

Code

#include<bits/stdc++.h>

#define LL long long
#define RG register
const int N = 300010;
using namespace std; inline int gi() {
RG int x = 0; RG char c = getchar(); bool f = 0;
while (c != '-' && (c < '0' || c > '9')) c = getchar();
if (c == '-') c = getchar(), f = 1;
while (c >= '0' && c <= '9') x = x*10+c-'0', c = getchar();
return f ? -x : x;
} struct node {
int v, s, fa, ch[2];
bool rev;
}t[N];
int S[N], top;
void putrev(int x) {
swap(t[x].ch[0], t[x].ch[1]);
t[x].rev ^= 1;
return ;
}
#define pushup(x) (t[x].s = (t[x].v^t[t[x].ch[0]].s^t[t[x].ch[1]].s))
void pushdown(int x) {
if (t[x].rev) {
if (t[x].ch[0]) putrev(t[x].ch[0]);
if (t[x].ch[1]) putrev(t[x].ch[1]);
t[x].rev = 0;
}
return ;
}
#define get(x) (t[t[x].fa].ch[1]==x)
bool isroot(int x) {
return (t[t[x].fa].ch[0] != x) && (t[t[x].fa].ch[1] != x);
}
void rotate(int x) {
int k = get(x), y = t[x].fa, z = t[y].fa;
if (!isroot(y)) t[z].ch[get(y)] = x;
t[x].fa = z;
t[t[x].ch[k^1]].fa = y, t[y].ch[k] = t[x].ch[k^1];
t[y].fa = x, t[x].ch[k^1] = y;
pushup(y);
return ;
}
void splay(int x) {
S[top = 1] = x;
for (RG int i = x; !isroot(i); i = t[i].fa) S[++top] = t[i].fa;
for (RG int i = top; i; i--) pushdown(S[i]);
while (!isroot(x)) {
int y = t[x].fa;
if (!isroot(y))
(get(x) ^ get(y)) ? rotate(x) : rotate(y);
rotate(x);
}
pushup(x);
return ;
}
void access(int x) {
for (int y = 0; x; y = x, x = t[x].fa)
splay(x), t[x].ch[1] = y, pushup(x);
return ;
}
void makeroot(int x) {
access(x); splay(x);putrev(x);
return ;
}
inline int findroot(int x) {
access(x); splay(x);
while (t[x].ch[0]) pushdown(x), x = t[x].ch[0];
return x;
}
void link(int x, int y) {
makeroot(x);
if (findroot(y) == x) return ;
t[x].fa = y;
return ;
}
void split(int x, int y) {
makeroot(x), access(y), splay(y);
return ;
}
void cut(int x, int y) {
makeroot(x);
if (findroot(y) == x && t[x].fa == y && !t[x].ch[1])
t[x].fa = t[y].ch[0] = 0, pushup(y);
return ;
} int main() {
int n = gi(), T = gi();
for (RG int i = 1; i <= n; i++) t[i].v = gi();
while (T--) {
int op = gi(), x = gi(), y = gi();
if (!op) {
split(x, y);
printf("%d\n", t[y].s);
}
else if (op == 1) link(x, y);
else if (op == 2) cut(x, y);
else {
access(x); splay(x); t[x].v = y; pushup(x);
}
}
return 0;
}

动态树Link-cut tree(LCT)总结的更多相关文章

  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. 洛谷P3690 [模板] Link Cut Tree [LCT]

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

  3. BZOJ 3282 Link Cut Tree (LCT)

    题目大意:维护一个森林,支持边的断,连,修改某个点的权值,求树链所有点点权的异或和 洛谷P3690传送门 搞了一个下午终于明白了LCT的原理 #include <cstdio> #incl ...

  4. Luogu 3690 Link Cut Tree

    Luogu 3690 Link Cut Tree \(LCT\) 模板题.可以参考讲解和这份码风(个人认为)良好的代码. 注意用 \(set\) 来维护实际图中两点是否有直接连边,否则无脑 \(Lin ...

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

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

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

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

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

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

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

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

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

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

  10. Link Cut Tree学习笔记

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

随机推荐

  1. tyvj P3737 逐个击破

    http://tyvj.cn/p/3737 时间: 1000ms / 空间: 131072KiB / Java类名: Main 描述 秉承伟大军事家的战略思想,作为一个有智慧的军长你,遇到了一个类似的 ...

  2. Python爬虫入门二之爬虫基础了解

    1.什么是爬虫 爬虫,即网络爬虫,大家可以理解为在网络上爬行的一直蜘蛛,互联网就比作一张大网,而爬虫便是在这张网上爬来爬去的蜘蛛咯,如果它遇到资源,那么它就会抓取下来.想抓取什么?这个由你来控制它咯. ...

  3. easyui-tabs扩展根据自定义属性打开页签

    .增加扩展 <script type="text/javascript" > /** * @author {kexb} easyui-tab扩展根据id切换页面 */ ...

  4. Open Type vs Open resource

    Open Type 可查询所有java 类型,包括.java .class Open Resource 只能打开 .java 等 ,不能打开 .class 相同点 都可以使用 ? * 通配符

  5. JavaEE互联网轻量级框架整合开发(书籍)阅读笔记(12):XML配置自动扫描包,自动加载*.properties文件

    一.XML和注解组合使用 前几篇的测试案例都是在Java类中配置,现在换一种使用方式,在XML中配置,使Spring IoC容器在启动之后自动去扫描配置的包路径,扫描加载指定路径下的propertie ...

  6. 编写高质量代码改善C#程序的157个建议——建议71:区分异步和多线程应用场景

    建议71:区分异步和多线程应用场景 初学者有时候会将异步和多线程混为一谈.如果对它们之间的区别不是很清楚,很容易写出下面这样的代码: private void buttonGetPage_Click( ...

  7. 编写高质量代码改善C#程序的157个建议——建议68:从System.Exception或其他常见的基本异常中派生异常

    建议68:从System.Exception或其他常见的基本异常中派生异常 微软建议:从System.Exception或其他常见基本异常之一派生异常.在Visual Studio中输入Excepti ...

  8. 使用JavaScript获取CSS伪元素属性

    我们可以通过DOM元素的 style 属性获取基本的CSS样式值, 但怎么获取CSS伪元素属性呢? 如下 // 获取 .element:before 的 color 值 var color = win ...

  9. Nutch2.x 集成ElasticSearch 抓取+索引

    http://blog.csdn.net/eryk86/article/details/14111811   使用https://github.com/apache/nutch.git导入nutch项 ...

  10. SELinux导致无法访问外网,PHP连接MySQL异常Can't connect to MySQL server、redis程序访问提示Redis server went away的解决方法

    今天上班遇到的问题,新配的Linux服务器,php.Apache和一系列扩展插件装好后,在本地好好的程序移上去就一直抱数据库连接错误,而用sql命令却能连接上去, 做了一个简单的判断数据库连接页面还是 ...