Link-cut Tree是一种支持改变树(森林)的形态(link和cut),同时维护树的路径上节点信息的数据结构。lct通过splay来维护每次的perferred path,说白了就是一个动态的树链剖分。splay的左右儿子分别代表preferred path上深度比它小和深度比它大的节点。

Link-cut Tree需要支持以下的操作:

1.access(x): 将节点x连接到perferred path上,返回值是一个节点,如果这是第一次access,则返回根节点,如果之前还access其他节点,则返回lca(last, x)。
2.makeroot(x): 将x这个节点作为根,也就是换根操作。
3.link(x,y): 连接x和y所在的子树。
4.cut(x,y): 将x和y之间的边删除。

我们先来看看access操作,借用Yang Zhe大神论文里的一张图来对access操作有一个形象的理解:

这一次access过后,从N到根的路径都变成了perferred path。

然后我们再来看看makeroot操作,我们单次makeroot操作就是把需要作为根的节点access,然后splay再到顶端,再通过给这个节点打上rev标记来将左右儿子交换。(不理解的可以画一张图理解一下。)
这下有了makeroot也有了access,就很容易地处理出一条链上的信息了,link就只要makeroot(a),fa[a]=b就好了,cut只要makeroot(a),access(b),splay(a),ch[a][0]=fa[b]=0就能解决。

参考模板:

//
// Title : LCT(change root)
// Date : 03.05.2016
// Test : BZOJ-2049
// Complexity : O(mlogn)
//
/*
对于有link和cut操作维护树上的信息等问题——
解决办法:link-cut tree
*/
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath> #ifdef WIN32
#define LL "%I64d"
#else
#define LL "%lld"
#endif #ifdef CT
#define debug(...) printf(__VA_ARGS__)
#define setfile()
#else
#define debug(...)
#define filename ""
#define setfile() freopen(filename".in", "r", stdin); freopen(filename".out", "w", stdout);
#endif #define R register
#define getc() (S == T && (T = (S = B) + fread(B, 1, 1 << 15, stdin), S == T) ? EOF : *S++)
#define dmax(_a, _b) ((_a) > (_b) ? (_a) : (_b))
#define dmin(_a, _b) ((_a) < (_b) ? (_a) : (_b))
#define cmax(_a, _b) (_a < (_b) ? _a = (_b) : 0)
#define cmin(_a, _b) (_a > (_b) ? _a = (_b) : 0)
char B[1 << 15], *S = B, *T = B;
inline int FastIn()
{
R char ch; R int cnt = 0; R bool minus = 0;
while (ch = getc(), (ch < '0' || ch > '9') && ch != '-') ;
ch == '-' ? minus = 1 : cnt = ch - '0';
while (ch = getc(), ch >= '0' && ch <= '9') cnt = cnt * 10 + ch - '0';
return minus ? -cnt : cnt;
}
#define maxn 200010
int n, m;
struct Node *null;
struct Node
{
bool rev;
Node *ch[2], *fa;
inline bool type()
{
return fa -> ch[1] == this;
}
inline bool check()
{
return this == fa -> ch[type()];
}
inline void set_rev()
{
std::swap(ch[0], ch[1]);
rev ^= 1;
}
inline void pushdown()
{
if (rev)
{
ch[0] -> set_rev();
ch[1] -> set_rev();
rev = 0;
}
}
void pushdownall()
{
if (check())
fa -> pushdownall();
pushdown();
}
inline void rotate()
{
R Node *f = fa;
R bool d = type();
(fa = f -> fa), f -> check() ? fa -> ch[f -> type()] = this : 0;
(f -> ch[d] = ch[!d]) != null ? ch[!d] -> fa = f : 0;
(ch[!d] = f) -> fa = this;
}
inline void splay(R bool need = 1)
{
if (need) pushdownall();
for (; check(); rotate())
if (fa -> check())
(type() != fa -> type() ? this : fa) -> rotate();
}
inline Node *access()
{
R Node *i = this, *j = null;
for (; i != null; i = (j = i) -> fa)
{
i -> splay();
i -> ch[1] = j;
}
return j;
}
inline void make_root()
{
access();
splay(0);
set_rev();
}
inline void link(R Node *that)
{
make_root();
fa = that;
}
inline void cut(R Node *that)
{
make_root();
that -> access();
splay(0);
that -> fa = ch[1] = null;
}
inline bool find(R Node *that)
{
access();
splay();
while (that -> fa != null)
that = that -> fa;
return that == this;
}
}mem[maxn];
int main()
{
// setfile();
n = FastIn(), m = FastIn();
null = mem;
null -> fa = null -> ch[0] = null -> ch[1] = null;
for (R int i = 1; i <= n; ++i) mem[i] = (Node) {0, {null, null}, null};
for (R int i = 1; i <= m; ++i)
{
R char opt;
while (opt = getc(), opt < 'A' || opt > 'Z');
R int a = FastIn(), b = FastIn();
if (opt == 'C')
{
(mem + a) -> link(mem + b);
}
else if (opt == 'D')
{
(mem + a) -> cut(mem + b);
}
else
{
puts((mem + a) -> find(mem + b) ? "Yes" : "No");
}
}
return 0;
}

练习建议:
BZOJ2002 [Hnoi2010]Bounce 弹飞绵羊
BZOJ2049 [Sdoi2008]Cave 洞穴勘测
BZOJ3282 Tree

【学习心得】Link-cut Tree的更多相关文章

  1. Link Cut Tree学习笔记

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

  2. 学习笔记:Link Cut Tree

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

  3. link cut tree 入门

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

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

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

  5. Codeforces Round #339 (Div. 2) A. Link/Cut Tree 水题

    A. Link/Cut Tree 题目连接: http://www.codeforces.com/contest/614/problem/A Description Programmer Rostis ...

  6. Link/cut Tree

    Link/cut Tree 一棵link/cut tree是一种用以表示一个森林,一个有根树集合的数据结构.它提供以下操作: 向森林中加入一棵只有一个点的树. 将一个点及其子树从其所在的树上断开. 将 ...

  7. 洛谷P3690 Link Cut Tree (模板)

    Link Cut Tree 刚开始写了个指针版..调了一天然后放弃了.. 最后还是学了黄学长的板子!! #include <bits/stdc++.h> #define INF 0x3f3 ...

  8. bzoj2049 [Sdoi2008]Cave 洞穴勘测 link cut tree入门

    link cut tree入门题 首先说明本人只会写自底向上的数组版(都说了不写指针.不写自顶向下QAQ……) 突然发现link cut tree不难写... 说一下各个函数作用: bool isro ...

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

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

  10. [CodeForces - 614A] A - Link/Cut Tree

    A - Link/Cut Tree Programmer Rostislav got seriously interested in the Link/Cut Tree data structure, ...

随机推荐

  1. cocos2dx基础篇(21) 进度条CCProgressTimer

    [3.x] (1)去掉 "CC" (2)CCProgressTimerType 改为强枚举 ProgressTimer::Type:: // RADIAL //扇形进度计时器 BA ...

  2. 用matplotlib对数据可视化

    下图是要用到的数据集,反映了从1984到2016年的失业率的变化 1.导入可视化模块import matlibplot.pyplot as plt, 函数plt.plot(x, y)确定折线图的点,x ...

  3. 为什么你的javascript学了这么久,水平还是烂成了渣?

    今年我给公司面试时,面试了百来个人,水平我就呵呵了,还觉得自己学了很久很厉害了,其实呢,渣的很呀,这篇文章送给想学好javascript找份工作的同学们. 首先要说明的是,咱现在不是高手,最多还是一个 ...

  4. P1067多项式输出

    这道题是2009普及组的题,仍然是一个字符串+模拟.(蒻到先不刷算法) 这道题的题干给了很多的提示,也很全面,但是当我把种种情况都考虑到了后,在写代码的过程中仍然出现了很多的错误,wa了三四次.其实导 ...

  5. POJ 3549 GSM phone(圆+扫描线+最短路)

    题目意思是求起点s到终点s的最短路,但是只能在圆的内部和边上走.一种可以想到的方法就是求出所有的交点,然后两两连边并验证合法性,但是这样的交点数规模有n2. 我们可以观察发现,我们在圆求并构成的图形中 ...

  6. 题解 AT2684 【K-City】

    此题这么水,竟然发题解的这么少. 本蒟蒻也来发一篇QwQ. 题目中所谓“四条街包围一个街区”其实就是两条街之间夹一个街区而已: n条街有几条两两相邻呢?答案是n-1条: m条街有几条两两相邻呢?答案是 ...

  7. POJ 3414 Pots (BFS/DFS)

    Pots Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 7783   Accepted: 3261   Special Ju ...

  8. Pose &&Get的区别

    从一个页面转向另一个页面的请求方式有两种,Post和Get. 如果从原理上来探究他们的区别,涉及到Http传输协议的细节,本文不加探究,只讨论一下表象. 1.Post传输数据时,不需要在URL中显示出 ...

  9. 375-基于TI DSP TMS320C6657、XC7K325T的高速数据处理核心板

    基于TI DSP TMS320C6657.XC7K325T的高速数据处理核心板 一.板卡概述    该DSP+FPGA高速信号采集处理板由我公司自主研发,包含一片TI DSP TMS320C6657和 ...

  10. DDD领域驱动设计初探(三):仓储Repository(下)

    前言:上篇介绍了下仓储的代码架构示例以及简单分析了仓储了使用优势.本章还是继续来完善下仓储的设计.上章说了,仓储的最主要作用的分离领域层和具体的技术架构,使得领域层更加专注领域逻辑.那么涉及到具体的实 ...