[算法模版]Link-Cut-Tree

博主懒本博客只对现有博客进行补充,先直接放隔壁链接。

FlashHu-LCT总结

Menci-LCT学习笔记

基本思想

即“使用一个splay维护一条链,且这条链不存在在原树上的深度相同的点”。而这条链在splay中的存储方式是以节点在原树上的深度为关键字进行排序。(这也意味着这个splay的中序遍历和这条链在原树上的中序遍历是相同的,且这个中序遍历就是把这个链从浅到深写下来)

push_up操作中这是个关键的性质。因为splay上的节点x的左子树就是他的一部分祖先节点,右子树就是他的一部分儿子节点。

makeroot操作

makeroot操作用于把任何一个点反转到当前树的根节点。

做法是先把要进行操作的节点x进行access,将root和x进行连通。然后进行splay(x)操作,把x变成splay的根。(请注意,这时候x在主树的深度仍然没有改变)。

随后将x的子树全部进行反转操作。也就是改变了这个splay的深度。虽然splay和splay之间的连接需要依赖深度关系(一棵splay的虚边连接向当前splay中序遍历序列的首位在原树上的父亲)。但是因为相对关系不变,所以不影响。

看图(图来自 动态仙人掌系列题解之四):

可以把连接老根和新根的splay看作一个无法弯曲的杆子,其他splay都是连接在杆子上的块。旋转操作虽然会改变杆子上每一点的深度,但是却不会改变块和杆子上连接点的相对深度关系。所以不会这样变换老根和新根不会对树的结构造成破坏。

另外如果维护的值是和树的形态相关的,这样使用makeroot很可能就会出锅(比如 SP2939 QTREE5 - Query on a tree V)。那么makeroott就不能使用了。因为涉及makeroot的操作有link,cut,split。我们得想办法解决这个问题:

  • Link之所以需要在linkmakeroot(x),是因为根据定义,对于一条虚边u,v,在原树上是一条连接u,root[v]的边(这里root[]是splay的root)。所以我们需要保证连接的其中一个端点f[x]=0且root[x]=x即可。

findroot操作

因为已经makeroot(x)了,所以x一定是最浅的点。我们必须要保证三个条件才能cut:

  1. 在同一棵树。
  2. y的父亲是x
  3. y没有左子树。

后两个条件保证了xy在原树上是直接连接的。

代码

洛谷3690

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<algorithm>
  4. #include<cmath>
  5. #define maxn (int)(3e5+1000)
  6. int f[maxn],v[maxn],s[maxn],st[maxn],c[maxn][2];
  7. bool r[maxn];
  8. using namespace std;
  9. int n,m;
  10. void pushr(int x){
  11. swap(c[x][0],c[x][1]);r[x]^=1;
  12. }
  13. void pushdown(int x){
  14. if(!r[x])return;
  15. if(c[x][0])pushr(c[x][0]);
  16. if(c[x][1])pushr(c[x][1]);
  17. r[x]=0;
  18. }
  19. void pushup(int x){
  20. s[x]=s[c[x][0]]^s[c[x][1]]^v[x];
  21. }
  22. bool nroot(int x){
  23. return c[f[x]][0]==x||c[f[x]][1]==x;
  24. }
  25. void rotate(int x){
  26. int y=f[x],z=f[y],k=(c[y][1]==x),w=c[x][!k];
  27. bool flag=nroot(y);
  28. c[y][k]=c[x][!k];
  29. f[c[x][!k]]=y;
  30. c[x][!k]=y;
  31. f[y]=x;
  32. if(flag)c[z][c[z][1]==y]=x;
  33. f[x]=z;
  34. pushup(y);
  35. pushup(x);
  36. }
  37. void splay(int x){
  38. int y=x,z=0;
  39. st[++z]=y;
  40. while(nroot(y))st[++z]=y=f[y];
  41. while(z)pushdown(st[z--]);
  42. for(;nroot(x);rotate(x)){
  43. y=f[x];
  44. if(!nroot(f[x]))continue;
  45. rotate((c[f[x]][0]==x)==(c[f[y]][0]==y)?y:x);
  46. }
  47. // pushup(x);
  48. }
  49. void access(int x){
  50. for(int y=0;x;y=x,x=f[x]){
  51. splay(x);c[x][1]=y;pushup(x);
  52. }
  53. }
  54. int findroot(int x){
  55. access(x);splay(x);
  56. while(c[x][0]){
  57. x=c[x][0];
  58. pushdown(x);
  59. }
  60. splay(x);
  61. return x;
  62. }
  63. void makeroot(int x){
  64. access(x);splay(x);pushr(x);
  65. }
  66. void split(int x,int y){
  67. makeroot(x);access(y);splay(y);
  68. }
  69. void link(int x,int y){
  70. if(findroot(x)!=findroot(y)){makeroot(x);f[x]=y;}
  71. }
  72. void cut(int x,int y){
  73. makeroot(x);
  74. if(findroot(y)==x&&f[y]==x&&!c[y][0]){
  75. f[y]=c[x][1]=0;
  76. pushup(x);
  77. }
  78. }
  79. int main(){
  80. scanf("%d%d",&n,&m);
  81. for(int i=1;i<=n;i++)scanf("%d",&v[i]);
  82. for(int i=1;i<=m;i++){
  83. int ty,x,y;scanf("%d%d%d",&ty,&x,&y);
  84. if(ty==0){
  85. split(x,y);
  86. printf("%d\n",s[y]);
  87. }
  88. else if(ty==1){
  89. link(x,y);
  90. }
  91. else if(ty==2){
  92. cut(x,y);
  93. }
  94. else if(ty==3){
  95. splay(x);v[x]=y;//pushup(x);
  96. }
  97. }
  98. }

易错点

  • 调用access(x)后,x所在splay的根可能不是x,也可能不是原树的根。所以在查询某条路径\(u,v\)的答案时,一定需要在makeroot(x),access(y)之后必须加上splay(x)splay(y),才能保证x或y在splay的根上。
  • findroot时应该先pushdown再判断左儿子是不是0,然后才能向左儿子走(因为可能左儿子原来不是0,pushdown之后变成了0,这时候走左儿子就会炸掉)。所以应该写成:while(c[x][0])x=c[x][0],push_down(x);
  • cut中判断条件合法会进行findroot(y),但是findroot(y)末尾如果没有对查询结果执行splay()就会锅掉。因为cut中会先makeroot(x)findroot(y)如果查询之后不把结果splay上去那么根就不是x了,接着cut就会出锅。

[算法模版]Link-Cut-Tree的更多相关文章

  1. link cut tree 入门

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

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

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

  3. Link/cut Tree

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

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

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

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

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

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

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

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

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

  8. Link Cut Tree学习笔记

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

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

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

  10. Link Cut Tree 总结

    Link-Cut-Tree Tags:数据结构 ##更好阅读体验:https://www.zybuluo.com/xzyxzy/note/1027479 一.概述 \(LCT\),动态树的一种,又可以 ...

随机推荐

  1. PHP小程序后端支付代码亲测可用

    小程序后端支付代码亲测可用 <?php namespace Home\Controller; use Think\Controller; class WechatpayController ex ...

  2. ELK学习笔记之filebeat合并多行日志示例

    0x00 概述 本节中的示例包括以下内容: 将Java堆栈跟踪日志组合成一个事件 将C风格的日志组合成一个事件 结合时间戳处理多行事件 同理,你可以把如下的正则应用在容器的yaml文件内. 0x01  ...

  3. WPF 精修篇 多属性触发器

    原文:WPF 精修篇 多属性触发器 多属性触发器就是多个属性都满足在触发 在属性触发器上加了一些逻辑判断 举栗子 这个栗子里  textBox 要满足俩个条件 才能触发背景变色 1)textbox的 ...

  4. 七雄Q传封包辅助技术探讨回忆贴

    前言 网页游戏2013年左右最火的类型最烧钱游戏,当年的我也掉坑了.为了边玩还满足码农精神我奋力的学习如何来做外挂.2013年我工作的第二个年头.多一半…介绍下游戏<七雄Q传>是北京游戏谷 ...

  5. .NET创建Windows定时任务

    创建Windows定时任务教程 1.创建一个控制台应用程序,保证程序正常运行. 2.右键点击我的电脑->点击管理. 3.在计算机管理弹出框->展开计算机管理(本地)->展开系统工具- ...

  6. .NetCore使用NLog写入数据库总结

    考虑到项目后期添加日志的需求,抽个闲暇时间学习一下使用NLog插件将日志信息写入到数据库中,完整项目见下面: 遇到的问题: 使用NLog写到SQLServer里面的中文显示问号? 解决方法:调整数据库 ...

  7. 01 .NET CORE 2.2 使用OCELOT -- 简单使用

    目前参考两篇文章,已实现基本的ocelot的网关功能. https://www.cnblogs.com/xlxr45/p/11320988.html https://www.jianshu.com/p ...

  8. Python - Win10系统下Python3.x环境配置

    Win10系统下Python3.x环境配置 https://blog.csdn.net/qq_41952474/article/details/82630551

  9. JSON,全称:JavaScript Object Notation,作为一个常见的轻量级的数据交换格

    JSON,全称:JavaScript Object Notation,作为一个常见的轻量级的数据交换格式,应该在一个程序员的开发生涯中是常接触的.简洁和清晰的层次结构使得 JSON 成为理想的数据交换 ...

  10. mac上使用Sequel Pro工具SSH连接数据库

    今天在使用Mac上的Sequel Pro连接线上的数据库时,一直报ssh通道连接失败.但是同样的公钥在另一台机器就可以,真是奇怪. 通过查找日志发现有一个关键字"key_load_publi ...