LCT,link-cut-tree,一种基于splay的高级数据结构,常用于维护动态森林问题,但ta只能维护子树信息,无法修改子树信息。

首先,如果你不会splay,来这里看看吧。

接下来步入正题。

首先阐述一下个人对LCT的理解,其实你可以把LCT理解成许多棵splay,每一个联通块是一棵大splay,每个大splay中有许多的小splay,小splay的根靠虚边连上大splay,虚边是什么?即假设你从x向y连一条虚边,便只要将x父亲设为y,不用将y的儿子设为x。

但每一棵小splay中的边都是正常的树边。那么,判断一个点是不是splay的根,就要这样

inline bool isroot(int x){return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x;}

那么,每棵小splay中的到底什么?你可以将其理解为你查询的历史路径。因为每当你要统计一条路径上的信息,就要用到access操作

inline void access(int x)
{
for(register int y=0;x;y=x,x=fa[x])
{
splay(x);ch[x][1]=y;push_up(x);
}
}

access看英文就知道,这个函数相当于打通了一条从该节点到root的通道,每次将这个点旋到当前splay的root,再将以前那一棵的root接到这一棵的右儿子上,就这样一路旋上去,最后,这个点会停在主splay的最下面。

inline void makeroot(int x)
{
access(x);splay(x);rev[x]^=1;
}

makeroot,顾名思义,把这个节点作为根,为什么要打翻转标记?因为LCT维护每个点的相对深度,当你把一个点旋到root,例如是一条链,你把点从最右边旋上来,那么本来这个点应该是最深的,现在变成最浅的了,所以打上翻转标记,使他依然是最深的。

当你要统计x到y路径上的某些信息是,只需要makeroot(x),access(y),这时,x到y中间的点就是你要的路径,再splay(y),y旋上去时push_up就会把路径上的信息统计掉,所以ans就是y点信息了。

int l[N];
inline void splay(int x)
{
l[0]=0;
int y=x;
while(1)
{
l[++l[0]]=y;
if(isroot(y))break;
y=fa[y];
}
Fordown(i,l[0],1)push_down(l[i]);
while(!isroot(x))
{
//if(!isroot(fa[x]))rotate(get(x)^get(fa[x])?x:fa[x]);
rotate(x);
}
}

这里的splay,因为有翻转操作,所以要先把路径上所有点入队,从上面开始依次下放翻转标记

inline int find(int x)
{
access(x);splay(x);
while(ch[x][0])x=ch[x][0];
return x;
}

find操作,其实就是找到左边的点,用来判断两个点在不在一个联通块中

inline void link(int x,int y)
{
if(find(x)==find(y))return;
makeroot(x);
fa[x]=y;
}
inline void cut(int x,int y)
{
makeroot(x);
access(y);splay(y);
if(ch[y][0]==x)ch[y][0]=0,fa[x]=0;
}

如果你弄清楚了前面几个操作,那么link和cut操作就很简单了

最后,在rotate的时候,如果你需要维护路径上的信息就需要push_up,但因为题目的不同而push_up的东西不一样,所以要根据题目来定,这里就拿维护路径上的^值,所以这样写

inline void push_up(int x){sum[x]=val[x]^sum[ch[x][0]]^sum[ch[x][1]];}

下面是例题

洛谷LCT模板(3690)要就维护路径^值

#include<bits/stdc++.h>
using namespace std;
typedef int sign;
typedef long long ll;
#define For(i,a,b) for(register sign i=(sign)a;i<=(sign)b;++i)
#define Fordown(i,a,b) for(register sign i=(sign)a;i>=(sign)b;--i)
const int N=3e5+5;
bool cmax(sign &a,sign b){return (a<b)?a=b,1:0;}
bool cmin(sign &a,sign b){return (a>b)?a=b,1:0;}
template<typename T>T read()
{
T ans=0,f=1;
char ch=getchar();
while(!isdigit(ch)&&ch!='-')ch=getchar();
if(ch=='-')f=-1,ch=getchar();
while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch-'0'),ch=getchar();
return ans*f;
}
void file()
{
#ifndef ONLINE_JUDGE
freopen("LCT.in","r",stdin);
freopen("LCT.out","w",stdout);
#endif
}
int n,m,val[N],sum[N];
int ch[N][2],fa[N],rev[N];
inline void push_up(int x){sum[x]=val[x]^sum[ch[x][0]]^sum[ch[x][1]];}
inline void push_down(int x)
{
if(rev[x])
{
rev[ch[x][0]]^=1;
rev[ch[x][1]]^=1;
swap(ch[x][0],ch[x][1]);
rev[x]=0;
}
}
inline bool isroot(int x){return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x;}
inline bool get(int x){return x==ch[fa[x]][1];}
inline void rotate(int x)
{
int old=fa[x],oldfa=fa[old],o=get(x);
if(!isroot(old))ch[oldfa][get(old)]=x;
fa[x]=oldfa;fa[ch[x][o^1]]=old;fa[old]=x;
ch[old][o]=ch[x][o^1];ch[x][o^1]=old;
push_up(old);push_up(x);
}
int l[N];
inline void splay(int x)
{
l[0]=0;
int y=x;
while(1)
{
l[++l[0]]=y;
if(isroot(y))break;
y=fa[y];
}
Fordown(i,l[0],1)push_down(l[i]);
while(!isroot(x))
{
if(!isroot(fa[x]))rotate(get(x)^get(fa[x])?x:fa[x]);
rotate(x);
}
}
inline void access(int x)
{
for(register int y=0;x;y=x,x=fa[x])
{
splay(x);ch[x][1]=y;push_up(x);
}
}
inline void makeroot(int x)
{
access(x);splay(x);rev[x]^=1;
}
inline int find(int x)
{
access(x);splay(x);
while(ch[x][0])x=ch[x][0];
return x;
}
inline void link(int x,int y)
{
if(find(x)==find(y))return;
makeroot(x);
fa[x]=y;
}
inline void cut(int x,int y)
{
makeroot(x);
access(y);splay(y);
if(ch[y][0]==x)ch[y][0]=0,fa[x]=0;
}
void work()
{
while(m--)
{
static int opt,x,y;
opt=read<int>();x=read<int>();y=read<int>();
if(opt==0)
{
makeroot(x);
access(y);splay(y);
printf("%d\n",sum[y]);
}
else if(opt==1)link(x,y);
else if(opt==2)cut(x,y);
else if(opt==3)
{
access(x);splay(x);
val[x]=y;push_up(x);
}
}
}
inline void input()
{
n=read<int>();m=read<int>();
For(i,1,n)sum[i]=val[i]=read<int>();
}
int main()
{
file();
input();
work();
return 0;
}

LCT动态树入门的更多相关文章

  1. BZOJ 2049: [Sdoi2008]Cave 洞穴勘测 (动态树入门)

    2049: [Sdoi2008]Cave 洞穴勘测 Time Limit: 10 Sec  Memory Limit: 259 MBSubmit: 1528  Solved: 644[Submit][ ...

  2. LCT 动态树 模板

    洛谷:P3690 [模板]Link Cut Tree (动态树) /*诸多细节,不注意就会调死去! 见注释.*/ #include<cstdio> #include<iostream ...

  3. [HNOI2010]弹飞绵羊 (平衡树,LCT动态树)

    题面 题解 因为每个点都只能向后跳到一个唯一的点,但可能不止一个点能跳到后面的某个相同的点, 所以我们把它抽象成一个森林.(思考:为什么是森林而不是树?) 子节点可以跳到父节点,根节点再跳就跳飞了. ...

  4. Fzu Problem 2082 过路费 LCT,动态树

    题目:http://acm.fzu.edu.cn/problem.php?pid=2082 Problem 2082 过路费 Accept: 528    Submit: 1654Time Limit ...

  5. Bzoj 2243: [SDOI2011]染色 树链剖分,LCT,动态树

    2243: [SDOI2011]染色 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 5020  Solved: 1872[Submit][Status ...

  6. Hdu 3966-Aragorn's Story LCT,动态树

    题目:http://acm.hdu.edu.cn/showproblem.php?pid=3966 Aragorn's Story Time Limit: 10000/3000 MS (Java/Ot ...

  7. Hdu 4010-Query on The Trees LCT,动态树

    Query on The Trees Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65768/65768 K (Java/Othe ...

  8. HDU4010 Query on The Trees (LCT动态树)

    Query on The Trees Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65768/65768 K (Java/Othe ...

  9. Hdu 2475-Box LCT,动态树

    Box Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submis ...

随机推荐

  1. 蜻蜓fm面试

    一面: 面试官首先看简历上写了在腾讯的实习,然后就探讨了半天,各种虚拟化的技术.... 说完之后,估计都半小时过去了,然后就又说了一下你用什么语言,你做的东西都比较偏底层呢,然后你对工作有什么要求吗? ...

  2. Java基础—异常

    一.概念 异常是程序中的一些错误,但并不是所有的错误都是异常,并且错误有时候是可以避免的. 异常体 Throwable:所有异常类的超类  Error:它表示不希望被程序捕获或者是程序无法处理的错误 ...

  3. AWK处理数组

    转自ChinaUnix论坛,感谢作者整理. 在文本处理的工作中,awk的数组是必不可少的工具,在这里,同样以总结经验和教训的方式和大家分享下我的一些学习心得,如有错误的地方,请大家指正和补充. awk ...

  4. 利用OVS+FLOODLIGHT,为数据表添加VLAN_ID和MPLS

    话不多说,直接上拓扑: 我这里是用主机h1 (10.0.0.1)ping 主机h2(10.0.0.2) 1.添加VLAN标签 v1: sudo ovs-ofctl add-flow m1-s1 in_ ...

  5. Java和C#基本类库的区别

    java.lang java .net Boolean System.Boolean Byte System. Byte Character System.Char Class System.Type ...

  6. stl源码剖析 详细学习笔记stack queue

    // //  stack.cpp //  笔记 // //  Created by fam on 15/3/15. // // //---------------------------15/03/1 ...

  7. 本科毕业平均年薪 30 万!经济寒冬挡不住 AI 人才的火热!

    互联网行业遭遇寒冬,企业纷纷裁员缩招,而 BAT 和硅谷明星公司对 AI 人才的投入却并不见放缓.为争夺相关人才,给应届毕业生开出的平均年薪高达 30 万. 而 TensorFlow 作为当下最流行的 ...

  8. wpf-典型的mvvm模式通用中小型管理系统框架0

    之前就一直在想着写这么一系列博客,将前段时间(也算有点久了)自己编写的一套框架分享下,和园子里的诸位大牛交流交流,奈何文思枯竭,提键盘而无从敲起,看来只有coding时才不会有这种裤子都脱了,才发现对 ...

  9. 《Linux内核分析》第一周学习报告

    第一周:计算机是如何工作的 姓名:王玮怡  学号:20135116 第一节 存储程序计算机工作模型(冯诺依曼体系结构) IP指向的内存地址,取指令执行,完成后,IP值自加一,取下一条指令再执行. AP ...

  10. 《linux内核设计与实现》第二章

    第二章 从内核出发 一.获取内核源码 1.使用Git(linux创造的系统) 使用git来获取最新提交到linux版本树的一个副本: $ git clone git://git.kernel.org/ ...