前言:这个算法似乎机房全都会,就我不会了TAT...强行搞了很久,勉强照着别人代码抄了一遍qwq

这个本人看论文实在看不懂,太菜了啊!!! 只好直接看如何实现...可是实现也看不太懂...

但直到我看到一篇大佬博客!!! point here 是真的讲的好,一点都不敷衍.真没收钱

本篇比较干货qwq(没图啊!!!) 一定要耐住性子学算法!!!

概念辨析

  • 但在之前还是要辨析几个概念:

辅助树

本人理解就是对于原树抽象出一个splay 或者说很多棵splay (啥,你告诉我原树是多叉树,splay只是一个二叉树)

其实就是将一个splay划分成很多部分(每一部分维护原图中的一条链) 然后对于这些部分连轻边.

(建议先认真看看那些基础概念) 然后对于一条链来说,深度两两不同,我们就可以用这个作为splay的键值来排序

然后这就可以维护出原树了... 为什么呢? 因为 虽然父亲只能有两个儿子,但是有很多儿子来认他啊qwq

(就像造树的时候只要给每个点一个fa就行了) 然后每条链又在splay中可以确定他们的先后顺序(也就是深度大小)

轻边和重边

这个不像树剖,这个就是随便给的(根据操作access来改变) 然后重边存在于splay中的子认父也认 的边, 也就是维护链时候的边. 然后轻边,就是只连到父亲时子认父不认 的边,就是一颗splay连到重链顶端父亲的那条边,而且一个点只能有一个重边!

操作介绍

然后就直接介绍操作吧(你还是没听懂?那看看别人博客的概念介绍吧qwq)

access

就是拉链,就是把一个点到根节点路径全都变为重边,且它是这条路径的一个端点.

如何实现呢qwq... 就是每次把当前这个节点splay到根,然后这个splay的父亲认了他这个儿子就行了,

接下来上传信息... 不断操作,直到到根 (注意要把他变为树的一个端点,所以要一开始要将它的儿子认为空的)

access=splay+child+push_up

make_root

使得一个点变为原树的根,然后这就可以便于维护路径信息了.

首先先把这个点access到根,之后将这个点splay到当前splay的根,然后再下放一个rev的标记就行了.

这是因为你使当前重链的深度完全翻转了(注意,我们splay是按照深度排序的!!!)

x就变为深度最小的点(即根节点)

make_root=access+splay+rev

find_root

找到原树的根,这个就易于判断连通性了(类似于并查集)

又是access到根,然后也是splay到根. (这样似乎很好维护一些东西,而且更方便去想了)

然后直接一直向左边走,最下面那个就是根节点了(深度最小, 时间复杂度因为有双旋所以可以保证)

而且在走左子树的时候要push_down!! (大佬博客上讲的,我还没被坑过qwq)

find_root=access+splay+go_left_child

split

将原图中的一条路径变为一条以它们为端点的重链.

假设我们split(x,y). 首先先把make_root(x)便于操作. 然后access(y),拉一条路径出来.

为了查找信息我们splay(y)splay的根上去,直接访问y的信息(中间splaypush_up)

split(x,y)=make_root(x)+access(y)+splay(y)

link

将原图中的两个点连一条边

我们把link(x,y)定义为把x的父亲认做y. (其实你互换也是可以的)

如果操作合法,我们只要make_root(x)然后x的父亲认做y就行了.

就是让x变为他所在树的根就行了qwq.. 不合法的话,就判断联通性就行了.

link(x,y)=make_root(x)+father[x]=y

cut

将原图中的一条边断掉

我们同样把cut(x,y)定义为把原图中x与其父亲y的边断掉. (同上互换也是可以的)

这个合法的话,直接把他们中的那条链split出来,直接断掉就行了...

不合法的话,同样尝试split出来,如果x的左儿子不是y就不行.

这样意义就是y在原树中不是x的父亲,不能cut掉.

cut(x,y)=split(x,y)+left_child[y]=fa[x]=0

至此link_cut_tree所有基础知识已经讲完qwq...然后高端操作只能自己做题了...

细节问题

这个lct细节是真的多,一不小心就调不出来了啊!!!

  1. rotate和普通的不同,要判断是不是当前splay的根!!!!

而且连边的时候一定要注意顺序啊!!!

就是判断is_root(u)之前不能连u-v的那条边!!!!

  1. splay那里也是 判断is_root的时候要注意对象啊,是fa[u]!!!

  2. make_root那里不能先交换一遍!!!直接打标记在那里就行了!!!

(有些人写法是先交换,再打左右儿子标记,我代码不同啊!!!)

  1. splayt要从o开始,然后判断!is_root(t)而不能从fa[o]开始,这是因为fa[o]可能为\(0\)啊!!!

  2. rotate中是push_up而不是push_down,前面splaypush_down完了啊!!!

代码

(没有注释....凑合对对,这道题是luogu模板)

#include <bits/stdc++.h>
#define debug cerr << "Pass" << endl
#define For(i, l, r) for(register int i = (l), i##end = (int)(r); i <= i##end; ++i)
#define Fordown(i, r, l) for(register int i = (r), i##end = (int)(l); i >= i##end; --i)
#define Set(a, v) memset(a, v, sizeof(a))
using namespace std; inline bool chkmin(int &a, int b) {return b < a ? a = b, 1 : 0;}
inline bool chkmax(int &a, int b) {return b > a ? a = b, 1 : 0;} inline int read() {
int x = 0, fh = 1; char ch = getchar();
for (; !isdigit(ch); ch = getchar()) if (ch == '-') fh = -1;
for (; isdigit(ch); ch = getchar()) x = (x * 10) + (ch ^ 48);
return x * fh;
} void File() {
#ifdef zjp_shadow
freopen ("P3690.in", "r", stdin);
freopen ("P3690.out", "w", stdout);
#endif
} const int maxn = 1e6 + 1e3; int val[maxn];
#define ls(u) ch[u][0]
#define rs(u) ch[u][1]
struct Link_Cut_Tree {
int fa[maxn], ch[maxn][2], rev[maxn], xsum[maxn]; inline bool is_root(int o) { return o != ls(fa[o]) && o != rs(fa[o]); } inline bool get(int o) { return o == rs(fa[o]); } inline void push_up(int o) { xsum[o] = xsum[ls(o)] ^ xsum[rs(o)] ^ val[o]; } inline void push_down(int o) {
if (rev[o]) { swap(ls(o), rs(o)); rev[ls(o)] ^= 1; rev[rs(o)] ^= 1; rev[o] = 0; }
} inline void rotate(int v) {
int u = fa[v], t = fa[u], d = get(v);
fa[ch[u][d] = ch[v][d ^ 1]] = u;
fa[v] = t; if (!is_root(u)) ch[t][rs(t) == u] = v;
fa[ch[v][d ^ 1] = u] = v;
push_up(u); push_up(v);
} int sta[maxn], top;
inline void splay(int u) {
sta[top = 1] = u;
for (register int t = u; !is_root(t); t = fa[t]) sta[++ top] = fa[t];
while (top) push_down(sta[top --]);
for (; !is_root(u); rotate(u)) if (!is_root(fa[u])) rotate(get(u) ^ get(fa[u]) ? u : fa[u]);
} inline void access(int o) { for (int t = 0; o; o = fa[t = o]) splay(o), rs(o) = t, push_up(o); } inline void make_root(int o) { access(o); splay(o); rev[o] ^= 1; } inline int find_root(int o) { access(o); splay(o); while (ls(o)) o = ls(o), push_down(o); splay(o); return o; } inline void split(int v, int u) { make_root(v); access(u); splay(u); } inline bool link(int v, int u) { make_root(v); if (find_root(u) == v) return false; fa[v] = u; return true; } inline void cut(int v, int u) { split(v, u); if (ls(u) == v) ls(u) = fa[v] = 0; }
} lct; int n, m; int main () {
File();
n = read(); m = read();
For (i, 1, n) val[i] = lct.xsum[i] = read();
For (i, 1, m) {
int opt = read(), x = read(), y = read();
if (!opt) { lct.split(x, y); printf ("%d\n", lct.xsum[y]); }
else if (opt == 1) lct.link(x, y);
else if (opt == 2) lct.cut(x, y);
else { lct.access(x); lct.splay(x); val[x] = y; lct.push_up(x); }
}
return 0;
}

link-cut-tree 简单介绍的更多相关文章

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

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

  2. link cut tree 入门

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

  3. Link/cut Tree

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

  4. Link Cut Tree学习笔记

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

  5. B - Link/Cut Tree

    Problem description Programmer Rostislav got seriously interested in the Link/Cut Tree data structur ...

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

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

  7. 学习笔记:Link Cut Tree

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

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

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

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

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

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

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

随机推荐

  1. Html5本地存储和本地数据库

    一个网站如何能在客户的浏览器存储更多的数据呢? 在Html4的时代在浏览器端存储点网站个性化的数据,尤其是用户浏览器的痕迹,用户的相关数据等一般只能存储在Cookie中,但是大多是浏览器对于Cooki ...

  2. iOS7动态调整文字大小

    iOS7添加了动态调整文字的大小,app可以通过接受通知的方式进行设置 iOS 7 introduces Dynamic Type, which makes it easy to display gr ...

  3. 940A Points on the line

    传送门 题目大意 给你n和d还有n个数,计算最少删除几个点可以是最大点与最小点之差小于等于d 分析 先对所有点排序,枚举每一个点ai到ai+d中有几个点,答案即n-其中最大的值 代码 #include ...

  4. 洛谷P1896 [SCOI2005]互不侵犯King【状压DP】

    题目描述 在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案.国王能攻击到它上下左右,以及左上左下右上右下八个方向上附近的各一个格子,共8个格子. 输入格式: 只有一行,包含两个数N,K ...

  5. Yii2 Ajax Post 实例及常见错误修正

    先贴下我的代码: signup.js$('.reg_verify_pic').click(function(){ var csrfToken = $('meta[name="_csrf-To ...

  6. Django静态文件路径设置

    提示 : Error fetching command 'collectstatic': You're using the staticfiles app without having set the ...

  7. 《设计模式之禅》--备忘录扩展:clone方式的备忘录

    接上篇<设计模式之禅>--策略扩展:策略枚举 需求:使用clone方式实现备忘录模式 发起人角色 public class Originator implements Cloneable ...

  8. URAL - 1153 Supercomputer 大数开方

    题意:给定m,m = n * (n+1) / 2,计算n值. 思路:n = SQRT(m*2) 注意m很大,需要自己实现大数开方.我用的是自己写的大数模板:大数模板 AC代码 #include < ...

  9. mac上搭建appium+IOS自动化测试环境(一)

    阅读须知 由于OS X系统最近才开始接触,所以有些东西也不是很清楚,这里只提供方法不提供原理,能解释清楚的我也会尽量解释.可能也有一些地方说的不严谨或有错的,还望大家指点一二. 实验环境 操作系统: ...

  10. win10安装mongodb及配置 和 mongodb的基本使用(node环境)

    mongodb安装 下载地址: https://www.mongodb.com/download-center 下载后,我们点击mongodb-win32-x86_64-2008plus-ssl-3. ...