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. 第13章 GPIO—位带操作

    第13章     GPIO—位带操作 全套200集视频教程和1000页PDF教程请到秉火论坛下载:www.firebbs.cn 野火视频教程优酷观看网址:http://i.youku.com/fire ...

  2. odoo自动更新表中数据

    这是追踪信息用的查询语句,__init__方法初始化作用 _order = ctx = dict(context or {}, mail_create_nolog=True) new_id = sup ...

  3. [Lydsy1805月赛]对称数 BZOJ5361

    分析: 这个题,还是蛮有趣的.考虑,如果l,r区间内的所有数出现奇数次,那么[l-1,r]的抑或和等于所得抑或和. 之后怎么维护呢,主席树维护区间抑或和,记得将每个点附上一个ull级别的随机数,之后抑 ...

  4. struts2_Interceptor

    题目要求:要求当未登录访问某些Action时,自动跳转到登录界面. 1. 2. 3. 4. 5.默认拦截器堆栈为defautStack,但一旦用户添加了拦截器,默认拦截器失效 6. 7. struts ...

  5. 关于EL表达式中requestScope和param区别

    今天演示EL表达式的时候发现自己jsp的基础实在是薄弱,在这个很简单的问题上迷惑了很久. 首先在看遇到的问题: 在浏览器地址输入,表示传入一个参数test,值为123 http://localhost ...

  6. CSS之Header--我的头部我做主

    <div class='header'> <div class="header-left"> <span class='iconfont back-i ...

  7. document.domain 跨域问题[转]

    document.domain用来得到当前网页的域名.比如打开百度,在地址栏里输入: javascript:alert(document.domain); //www.baidu.com 弹出窗体: ...

  8. 20155304 《网络对抗》Exp9 web安全基础实践

    20155304 <网络对抗>Exp9 web安全基础实践 实验后回答问题 (1)SQL注入攻击原理,如何防御 攻击原理:web应用程序对用户输入数据的合法性没有判断,攻击者可以在web应 ...

  9. 20155316 Exp1 PC平台逆向破解(5)M

    前绪 实验收获与感想 初步从三个途径了解了什么是缓冲区溢出以及如何简单实现它,对汇编与反汇编有更直观的了解. 什么是漏洞?漏洞有什么危害? 漏洞是指机器体制设计时所没有顾及到的.可以被利用的bug,放 ...

  10. 《网路对抗》Exp8 WEB基础实践

    20155336<网路对抗>Exp8 WEB基础实践 一.基础问题回答 1.什么是表单 表单是一个包含表单元素的区域,表单元素是允许用户在表单中(比如:文本域.下拉列表.单选框.复选框等等 ...