核心思想:

动态维护一个森林。支持删边和加边,查询链信息和连通块信息等很多操作。

由若干棵$Splay$组成,每棵$Splay$维护一条链,以深度作为关键字。

也就是说$Splay$的中序遍历相当于从上到下遍历这条链。

$Splay$中的边是实边,将两个$Splay$相连的边是虚边。

实边的父亲有它这个儿子(双向关系),虚边的父亲没有它这个儿子(单向关系)。

组成$LCT$的基础操作:(以下均认为$LCT$中只有一棵树)

$access(x)$:打通根到$x$的路径,使一棵包含且仅包含根到$x$这条链上点的$Splay$出现。

实现方法:

1.$splay(x)$:将$x$转到当前$Splay$的根。(此时$x$是该$Splay$中最深的点,没有右儿子)

2.$c[x][1]=y$:将$x$的右儿子设为刚才操作的$Splay$的根。

3.$x=f[x]$:继续操作$x$在原树中的父亲,若$x$已经为根则退出。

$makeroot(x)$:使$x$成为根。

实现方法:

1.$access(x)$。

2.$splay(x)$。

3.翻转整棵$Splay$。

为什么不能只翻转$x$的左右儿子:一个链提末端点当根之后整个链的深度顺序全部翻转。

如:$1-2-3$翻转后为$3-2-1$而不是$3-1-2$。

$findroot(x)$:找$x$所在原树的根。

实现方法:

1.$access(x)$。

2.$splay(x)$。

3.在$Splay$上一直往左走,最终走到答案点$y$。

3.$splay(y)$。

$split(x,y)$:拉出路径$(x,y)$成为一个$Splay$,并令$x$为原树的根。

实现方法:

1.$makeroot(x)$。

2.$access(y)$。

$link(x,y)$:连一条边$(x,y)$。

实现方法:

1.$makeroot(x)$。

2.若$findroot(y)\neq x$则$f[x]=y$。

$cut(x,y)$:断开边$(x,y)$。

实现方法:

1.若$findroot(x)=findroot(y)$则$split(x,y)$。

2.若$f[y]=x$且$c[y][0]=0$则$f[y]=c[x][1]=0$。

代码:

#include<bits/stdc++.h>
#define maxn 100005
#define maxm 500005
#define inf 0x7fffffff
#define ll long long using namespace std;
int N,M,rc,A[maxn],s[maxn],st[maxn];
int r[maxn],c[maxn][],f[maxn]; inline int read(){
int x=,f=; char c=getchar();
for(;!isdigit(c);c=getchar()) if(c=='-') f=-;
for(;isdigit(c);c=getchar()) x=x*+c-'';
return x*f;
} inline bool nroot(int x){return c[f[x]][]==x||c[f[x]][]==x;}
inline void pushr(int x){swap(c[x][],c[x][]),r[x]^=;}
inline void pushup(int x){s[x]=s[c[x][]]^s[c[x][]]^A[x];}
inline void pushdown(int x){
if(r[x]){
if(c[x][]) pushr(c[x][]);
if(c[x][]) pushr(c[x][]);
r[x]=;
}
}
inline void rotate(int x){
int y=f[x],z=f[y],k=(c[y][]==x),w=c[x][!k];
if(nroot(y)) c[z][c[z][]==y]=x;
c[x][!k]=y,c[y][k]=w;
if(w) f[w]=y;
f[y]=x,f[x]=z;
pushup(y);
}
inline void splay(int x){
int y=x,z=; st[++z]=y;
while(nroot(y)) st[++z]=y=f[y];
while(z) pushdown(st[z--]);
while(nroot(x)){
y=f[x],z=f[y];
if(nroot(y)) rotate(((c[y][]==x)^(c[z][]==y))?x:y);
rotate(x);
}
pushup(x);
}
inline void access(int x){for(int y=;x;x=f[y=x]) splay(x),c[x][]=y,pushup(x);}
inline void makeroot(int x){access(x),splay(x),pushr(x);}
inline void split(int x,int y){makeroot(x),access(y),splay(y);}
inline int findroot(int x){
access(x),splay(x);
while(c[x][]) pushdown(x),x=c[x][];
splay(x); return x;
}
inline void link(int x,int y){makeroot(x);if(findroot(y)!=x) f[x]=y;}
inline void cut(int x,int y){makeroot(x);if(findroot(y)==x && f[y]==x && !c[y][])f[y]=c[x][]=,pushup(x);} int main(){
N=read(),M=read();
for(int i=;i<=N;i++) A[i]=read();
while(M--){
int op=read(),x=read(),y=read();
if(op==) split(x,y),printf("%d\n",s[y]);
if(op==) link(x,y);
if(op==) cut(x,y);
if(op==) splay(x),A[x]=y;
}
return ;
}

LCT

【模板】LCT的更多相关文章

  1. 模板—LCT

    #include<iostream> #include<cstring> #include<cstdio> #define LL long long using n ...

  2. LCT 模板及套路总结

    这一个月貌似已经考了无数次\(LCT\)了..... 保险起见还是来一发总结吧..... A. LCT 模板 \(LCT\) 是由大名鼎鼎的 \(Tarjan\) 老爷发明的. 主要是用来维护树上路径 ...

  3. BZOJ2002 & LCT模板(分块不会搞)

    题意: 看题. 某天,Lostmonkey发明了一种超级弹力装置,为了在他的绵羊朋友面前显摆,他邀请小绵羊一起玩个游戏.游戏一开始,Lostmonkey在地上沿 着一条直线摆上n个装置,每个装置设定初 ...

  4. LCT模板

    之前一直用的LCT模板,因为其实个人对LCT和Splay不是很熟,所以用起来总觉得略略的坑爹,过了一段时间就忘了,但事实上很多裸的LCT要改的东西是不多的,所以今天写了些注释,以后可能套起模板来会得心 ...

  5. bzoj2049-洞穴勘测(动态树lct模板题)

    Description 辉辉热衷于洞穴勘测.某天,他按照地图来到了一片被标记为JSZX的洞穴群地区.经过初步勘测,辉辉发现这片区域由n个洞穴(分别编号为1到n)以及若干通道组成,并且每条通道连接了恰好 ...

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

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

  7. Luogu 3690 LCT - 模板

    推荐几篇比较好的博客: FlashHu 的 讲解比较好 : 传送门 Candy 的 代码~ : 传送门 以及神犇Angel_Kitty的 学习笔记: 传送门 Code V 模板 #include< ...

  8. 动态树LCT(Link-cut-tree)总结+模板题+各种题目

    一.理解LCT的工作原理 先看一道例题: 让你维护一棵给定的树,需要支持下面两种操作: Change x val:  令x点的点权变为val Query x y:  计算x,y之间的唯一的最短路径的点 ...

  9. 洛谷P3690 [模板] Link Cut Tree [LCT]

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

  10. 模板—数据结构—LCT

    模板—数据结构—LCT Code: #include <cstdio> #include <algorithm> using namespace std; #define N ...

随机推荐

  1. Android Scrollview嵌套下listView动态加载数据,解决onScrollChanged执行多次数据重复问题

    这一篇博客和上一篇讲的都是listView的动态加载,但有所不同的是,本篇的listView是嵌套在ScrollView下的,有时候在一个Activity中可能分为好几个模块,由于展示的需要(手机屏幕 ...

  2. 爬取 豆瓣电影Top250

    目标 学习爬虫,爬豆瓣榜单,获取爬取静态页面信息的能力 豆瓣电影 Top 250  https://movie.douban.com/top250 代码 import requests from bs ...

  3. python应用之socket编程

    tcp/udp下的socket的基本使用 基于tcp的socket Tcp是基于链接的,必须先启动服务端,然后启动客户端进行链接 服务端: ss = socket() #创建服务器套接字 ss.bin ...

  4. 使用Psi Probe监控Tomcat8.5

    一.从GitHub上下载Psi Probe的war包 https://github.com/psi-probe/psi-probe/releases 可以看到当前最新版是3.3.1,下载 probe. ...

  5. qr.h

    创建二维码 QRCodeCreate vc++

  6. 201871010109-胡欢欢《面向对象程序设计(java)》第二周学习总结

    开头: 项目 内容 这个作业属于哪个课程 <任课教师博客主页链接>     https://www.cnblogs.com/nwnu-daizh/ 这个作业的要求在哪里 <作业链接地 ...

  7. 201871010118-唐敬博《面向对象程序设计(Java)》第二周学习总结

    博文正文开头格式:(3分) 项目 内容 这个作业属于哪个课程 https://www.cnblogs.com/nwnu-daizh/ 这个作业的要求在哪里 https://www.cnblogs.co ...

  8. 201871010131-张兴盼《面向对象程序设计(java)》第二周学习总结

    项目 内容 <面向对象程序设计(java)> https://home.cnblogs.com/u/nwnu-daizh/ 这个作业的要求在哪里 https://www.cnblogs.c ...

  9. 进程及Python实现

    进程杂谈 #进程就是正在执行的一个过程,是对正在运行程序的一个抽象 #进程由程序.数据集和进程控制块(最重要的,进程切换 状态如何保存,恢复和记录)组成 """ 进程调度 ...

  10. POJ2239-Selecting Courses-(匈牙利算法)

    题意:n门课,每门各自有t个开课时间,在不冲突的情况下选最多课. 题解:把周p第q节课转化为数值sum,表示在一周7*12节课中排第几节,用二分图最大匹配. #include<stdio.h&g ...