link-cut-tree 简单介绍

目录

  • 概念辨析
    • 辅助树
    • 轻边和重边
  • 操作介绍
    • access
    • make_root
    • find_root
    • split
    • link
    • cut
  • 细节问题
  • 代码

前言:这个算法似乎机房全都会,就我不会了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(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_shadowfreopen ("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;
}

转载于:https://www.cnblogs.com/zjp-shadow/p/8551548.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/369438.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

linux svn 看不到文件,SVN更新时不能打开新文件svn-base系统找不到指定的文件

svn服务器架设在linux系统上&#xff0c;svn客户端在windows上&#xff0c;在update的时候可能会出现“Can’t open file.XXXX/tmp/text-base/XX.svn-base 系统找不到指定的文件”的错误。这是由于Linux服务器上的目标文件中存在两个相同文件名的文件。因为linux系统的文件名区…

C++primer 13.2.1节练习

练习13.23 1 #include <iostream>2 #include <string>3 #include <memory>4 5 using namespace std;6 7 8 class HasPtr {9 friend ostream &print(ostream &os, HasPtr &h); 10 public: 11 HasPtr(const string &s string()) : ps…

编年史与微云

总览 我面临的一个常见问题是&#xff1a; 如果是单个作者&#xff0c;多个读者&#xff0c;您如何扩展基于Chronicle的系统。 尽管有解决此问题的方法&#xff0c;但很有可能根本不会出现问题。 微云 这是我用来描述单个线程来完成当前由多个服务器完成的工作的术语。 &#…

去除IE10自带的清除按钮

最近在工作中碰到了一个问题&#xff0c;原本在IE8&#xff0c;IE9下正常的input表单&#xff0c;在IE10下会出现清除按钮&#xff0c;即表单右侧会出现一个可以清除该表单内容的小叉。由于之前一直没有兼容过IE10&#xff0c;所以我专门搜了下原因。发现&#xff0c;该功能是微…

Linux/CentOS7install PackageError: Loaded plugins: fastestmirror

Centons7 其大概意思是fastestmirror不能使用&#xff0c;fastestmirror是yum的一个加速插件&#xff0c;具体我也没有仔细了解过&#xff0c;可能是系统不支持或者缺少组件导致的。 处理办法就是禁用这个插件&#xff0c;方法如下&#xff1a; [rootlocalhost ~]# vim /etc/yu…

不要仅仅依靠单元测试

当您构建一个复杂的系统时&#xff0c;仅仅测试组件是不够的。 这很关键&#xff0c;但还不够。 想象一下一家汽车厂生产并进口最高质量的零件&#xff0c;但组装好之后再也不会启动发动机了。 如果您的测试用例套件几乎不包含单元测试&#xff0c;则您将永远无法确保系统整体正…

spring mvc的工作原理

该文转载自&#xff1a;http://blog.csdn.net/u012191627/article/details/41943393 SpringMVC框架介绍 1) spring MVC属于SpringFrameWork的后续产品&#xff0c;已经融合在Spring Web Flow里面。 Spring 框架提供了构建 Web 应用程序的全功能 MVC 模块。使用 Spring 可插入的…

oracle快速插入大量数据

方法一&#xff1a;循环 declare -- Local variables here m integer; begin -- Test statements here--输出开始时间 dbms_output.put_line(start:||sysdate); m:0;--循环插入的数据量 for i in 1..4000 loop m:m1; --插入语句&#xff0c;其中admintest||m, 为admintest后面…

春天遇见Apache Hadoop

SpringSource 刚刚宣布了适用于Apache Hadoop的Spring的第一个GA版本 。 该项目的目的是简化基于Hadoop的应用程序的开发。 您可以下载该项目在这里 &#xff0c;并检查了Maven的文物在这里 。 Apache Hadoop的Spring诞生是为了解决Hadoop应用程序构建不良的问题&#xff0c;…

linux 模拟时序,stm32GPIO模拟时序读写nandflash(K9F1G08U0B)问题

我使用的STM32F103VBT6这款芯片,K9F1G08U0B和 STM32F103VBT6连接接口有如下对应关系:ALE——PA1WE——PA2WP——PA3R\B——PC0RE——PC1CE——PC2CLE——PC38位IO口对应PE0——PE7下面4个函数&#xff0c;对应的是读取设备的ID&#xff0c;我在main函数里调用函数Nand_Flash_Re…

pat 甲级 1072. Gas Station (30)

1072. Gas Station (30) 时间限制200 ms内存限制65536 kB代码长度限制16000 B判题程序Standard作者CHEN, YueA gas station has to be built at such a location that the minimum distance between the station and any of the residential housing is as far away as possibl…

骑士周游问题

骑士周游问题 问题&#xff1a;在一个 8*8 的棋盘上&#xff0c;马按照“日”字走&#xff0c;给定一个起点&#xff0c;打印出马不重复的走完棋盘64个格子的路径。 解答&#xff1a;递归 回溯 &#xff08;对于任一步&#xff0c;马能走的下一步有8个方向&#xff0c;但是需要…

那些容易遗忘的web前端问题

背景&#xff1a; 年底将至&#xff0c;本人这只才出门的前端菜鸟&#xff0c;终于有空闲的时间来整理一下最近投简历时出现的问题。有的是经常使用但是没有仔细留意造成的&#xff1b;有的是个人认为根本没人使用而忽略的。为了下次不出现这种错误&#xff0c;进行一下总结。…

使用IntelliJ IDEA的原因

介绍 我经常遇到一个问题&#xff0c;为什么我使用Intellij来支持另一个IDE&#xff08;在本例中为Eclipse&#xff09;。 大多数时候&#xff0c;我会通过演示IntelliJ的某些功能并展示一切的集成程度来回答这个问题。 这让我开始思考使用它的真正原因是什么。 这篇文章将试图…

linux光标美化包,使用 [ powerlevel10k ] 美化你的WSL (Linux)

使用 [ powerlevel10k ] 美化你的WSL (Linux)使用 [ powerlevel10k ] 美化你的WSL (Linux)前言关于linux终端的美化&#xff0c;网上的教程有很多&#xff0c;但对于国内的用户来说&#xff0c;效果往往是这样的&#xff1a;教程中通过以下命令安装 oh-my-zshsh -c "$(cur…

HashMap实现原理分析

1 HashMap的数据结构 数据结构中有数组和链表来实现对数据的存储&#xff0c;但这两者基本上是两个极端。 数组 数组存储区间是连续的&#xff0c;占用内存严重&#xff0c;故空间复杂的很大。但数组的二分查找时间复杂度小&#xff0c;为O(1)&#xff1b;数组的特点是&#xf…

opencv3.2.0在vs2015下安装与配置

准备工作 VS2015OpenCV 3.2.0OpenCV配置环境变量&#xff0c;path下添加\opencv\build\x64\vc14\bin&#xff0c;新设置的环境变量需要重启才能使用测试工程 新建VC控制台空项目修改平台为x64&#xff0c;这一步先做源文件中加入main.cpp&#xff0c;测试代码&#xff1a;#incl…

CSS实现响应式布局(自动拆分几列)

1.css代码 <style type"text/css">.container{margin-top: 10px;}.outerDiv{float:left;width:100%;}/* 大于648像素一行两个div&#xff0c;innerDiv两个宽度为&#xff1a;(300 4 20)*2 */media screen and (min-width: 648px){.outerDiv {width: 50%}}.inne…

如何使用字节序列化双精度数组(二进制增量编码,用于低差单调浮点数据集)...

低延迟系统需要高性能的消息处理和传递。 由于在大多数情况下&#xff0c;数据必须通过有线传输或进行序列化才能保持持久性&#xff0c;因此编码和解码消息已成为处理管道的重要组成部分。 高性能数据编码的最佳结果通常涉及应用程序数据细节的知识。 本文介绍的技术是一个很好…

error

for(int i1;i<size;i) { if(ba[i]) { pos i1; break; } }输入&#xff1a; a{4,5,7,4,6,8},b4 输出&#xff1a; 位置是4&#xff08;错误&#xff0c;这儿应该是1&#xff0c;但程序未失败。&#xff09;改成&#xff1a;for(int i0;i<size;i) { if(ba[i]) { pos i1; …