Link-cut tree(LCT)【可以理解为树链剖分+splay】

给出如下定义:

  access(x):访问x节点

  perferred child:若以x为根的子树中最后被访问的节点在以x的儿子y为根的子树中,则称y为节点x的preferred child

  preferred edge:节点x与其preferred child之间的边

  preferred path:由preferred edge组成的路径

每条preferred path用splay维护,记录splay的根接到上条重链的哪个节点

操作

  每次访问一个点时,该点一直到根的路径上的点全部被修改,与preferred child断开并连到新的preferred child上,并打上翻转标记,也就是拆分(cut)和合并(link)两个操作,其余链上的维护可以通过下传标记(pushdown)解决

例题:

  bzoj2002弹飞绵羊

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
const int Mx=;
int n,m,fa[Mx],l[Mx],r[Mx],root[Mx],siz[Mx],rev[Mx];
void pushup(int x) { siz[x]=siz[l[x]]+siz[r[x]]+; }
void pushdown(int x) { if(rev[x]) rev[x]^=,rev[l[x]]^=,rev[r[x]]^=,swap(l[x],r[x]); }
void rotate(int x)
{
int y=fa[x];
if(l[y]==x) l[y]=r[x],fa[r[x]]=y,r[x]=y,fa[x]=fa[y],fa[y]=x;
else r[y]=l[x],fa[l[x]]=y,l[x]=y,fa[x]=fa[y],fa[y]=x;
if(root[y]) root[y]=,root[x]=;
else
if(r[fa[x]]==y) r[fa[x]]=x;
else l[fa[x]]=x;
pushup(y);
}
void splay(int x)
{
while(!root[x])
{
int y=fa[x],yy=fa[y];
if(root[y]) rotate(x);
else
if((l[yy]==y&&l[y]!=x)||(l[yy]!=y&&l[y]==x)) rotate(y),rotate(x);
else rotate(x),rotate(x);
}
pushup(x);
}
void access(int x)
{
int y=;
while(x)
{
splay(x); root[r[x]]=,root[y]=;
pushup(x); r[x]=y,y=x,x=fa[x];
}
}
void rever(int x) { access(x); splay(x); rev[x]^=; }
void link(int x,int y) { rever(x); fa[l[x]]=,root[l[x]]=,l[x]=,fa[x]=y; pushup(x); }
void cut(int x,int y) { rever(x); access(y); splay(y); l[y]=,fa[x]=; }
int main()
{
scanf("%d",&n);
for(int i=;i<=n;i++) root[i]=,siz[i]=;
for(int i=;i<=n;i++)
{
int x; scanf("%d",&x);
if(i+x<=n) link(i,i+x);
}
scanf("%d",&m);
while(m--)
{
int num,x,k; scanf("%d",&num);
if(num==)
{
scanf("%d",&x); x++;
rever(x);
printf("%d\n",siz[l[x]]+);
}
else
{
scanf("%d%d",&x,&k); x++;
if(x+k>n) link(x,);
else link(x,x+k);
}
}
}

  bzoj2631 tree

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
const int Mx=;
const int p=;
int n,top,q[Mx],fa[Mx],son[Mx][],siz[Mx],rev[Mx];
unsigned int val[Mx],sum[Mx],add_tag[Mx],mul_tag[Mx];
inline int read()
{
int x=,f=;char ch=getchar();
while(ch<''||ch>''){if(ch=='-')f=-;ch=getchar();}
while(ch>=''&&ch<=''){x=x*+ch-'';ch=getchar();}
return x*f;
}
void cal(int x,int a,int b)
{
if(!x) return ;
val[x]=(a*val[x]+b)%p;
sum[x]=(a*sum[x]+b*siz[x])%p;
add_tag[x]=(a*add_tag[x]+b)%p;
mul_tag[x]=(a*mul_tag[x])%p;
}
int isroot(int x)
{
if(son[fa[x]][]!=x&&son[fa[x]][]!=x) return ;
return ;
}
void pushup(int x)
{
int l=son[x][],r=son[x][];
sum[x]=(sum[l]+sum[r]+val[x])%p;
siz[x]=(siz[l]+siz[r]+)%p;
}
void pushdown(int x)
{
int l=son[x][],r=son[x][];
if(rev[x])
rev[x]^=,rev[l]^=,rev[r]^=,
swap(son[x][],son[x][]);
int a=add_tag[x],m=mul_tag[x];
add_tag[x]=,mul_tag[x]=;
if(a!=||m!=) cal(l,m,a),cal(r,m,a);
}
void rotate(int x)
{
int l=,r=,y=fa[x],yy=fa[y];
if(son[y][]==x) l=; r=l^;
if(!isroot(y)) son[yy][(son[yy][]==y)]=x;
fa[x]=yy,fa[y]=x,fa[son[x][r]]=y,son[y][l]=son[x][r],son[x][r]=y;
pushup(y);pushup(x);
}
void splay(int x)
{
q[++top]=x;
for(int i=x;!isroot(i);i=fa[i]) q[++top]=fa[i];
while(top) pushdown(q[top--]);
while(!isroot(x))
{
int y=fa[x],yy=fa[y];
if(!isroot(y))
{
if((son[y][]==x)^(son[yy][]==y)) rotate(x);
else rotate(y);
}
rotate(x);
}
}
void access(int x)
{
for(int t=;x;t=x,x=fa[x])
splay(x),son[x][]=t,pushup(x);
}
void rever(int x)
{
access(x); splay(x); rev[x]^=;
}
void link(int x,int y)
{
rever(x); fa[x]=y;
}
void split(int x,int y)
{
rever(y); access(x); splay(x);
}
void cut(int x,int y)
{
rever(x); access(y); splay(y);
son[y][]=fa[x]=;
}
signed main()
{
int m; scanf("%d%d",&n,&m);
for(int i=;i<=n;i++) val[i]=sum[i]=mul_tag[i]=siz[i]=;
for(int i=,x,y;i<n;i++) scanf("%d%d",&x,&y),link(x,y);
while(m--)
{
char ch[]; scanf("%s",ch); int x,y,c; x=read(),y=read();
if(ch[]=='+') c=read(),split(x,y),cal(x,,c);
if(ch[]=='-') cut(x,y),x=read(),y=read(),link(x,y);
if(ch[]=='*') c=read(),split(x,y),cal(x,c,);
if(ch[]=='/') split(x,y),printf("%d\n",sum[x]);
}
return ;
}

LCT(Link-Cut Tree)的更多相关文章

  1. LCT(Link Cut Tree)总结

    概念.性质简述 首先介绍一下链剖分的概念链剖分,是指一类对树的边进行轻重划分的操作,这样做的目的是为了减少某些链上的修改.查询等操作的复杂度.目前总共有三类:重链剖分,实链剖分和并不常见的长链剖分. ...

  2. FOJ题目Problem 2082 过路费 (link cut tree边权更新)

    Problem 2082 过路费 Accept: 382    Submit: 1279 Time Limit: 1000 mSec    Memory Limit : 32768 KB Proble ...

  3. bzoj 3282: Tree (Link Cut Tree)

    链接:https://www.lydsy.com/JudgeOnline/problem.php?id=3282 题面: 3282: Tree Time Limit: 30 Sec  Memory L ...

  4. HDOJ 题目2475 Box(link cut tree去点找祖先)

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

  5. POJ 题目3237 Tree(Link Cut Tree边权变相反数,求两点最大值)

    Tree Time Limit: 5000MS   Memory Limit: 131072K Total Submissions: 6131   Accepted: 1682 Description ...

  6. BZOJ 题目1036: [ZJOI2008]树的统计Count(Link Cut Tree,改动点权求两个最大值和最大值)

    1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec  Memory Limit: 162 MB Submit: 8421  Solved: 3439 [Submi ...

  7. URAL 题目1553. Caves and Tunnels(Link Cut Tree 改动点权,求两点之间最大)

    1553. Caves and Tunnels Time limit: 3.0 second Memory limit: 64 MB After landing on Mars surface, sc ...

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

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

  9. LuoguP3690 【模板】Link Cut Tree (动态树) LCT模板

    P3690 [模板]Link Cut Tree (动态树) 题目背景 动态树 题目描述 给定n个点以及每个点的权值,要你处理接下来的m个操作.操作有4种.操作从0到3编号.点从1到n编号. 0:后接两 ...

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

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

随机推荐

  1. Android(java)学习笔记105:Android启动过程(转载)

    转载路径为: http://blog.jobbole.com/67931/ 1. 关于Android启动过程的问题: 当按下Android设备电源键时究竟发生了什么? Android的启动过程是怎么样 ...

  2. [R] 简单笔记(一)

    library(lattice) xyplot(Petal.Length~Petal.Width,data=iris,goups = Species)//画分类图 plot(model,subdata ...

  3. AutoWidthInput

    import React from 'react'; import PropTypes from 'prop-types'; class AutoWidthInput extends React.Co ...

  4. Java执行系统命令工具类(JDK自带功能)

    CommandUtil.java package utils; import java.io.ByteArrayOutputStream; import java.io.IOException; im ...

  5. Hibernate异常:identifier of an instance of 错误

    今天写项目时,在使用hibernate封装的插入方法时,由于需要同时保存多个数据,导致出现identifier of an instance of 如下代码 :(由于最大最小分数不同所以需要插入两条数 ...

  6. Bootstrap历练实例:带表格的面板

    带表格的面板 为了在面板中创建一个无边框的表格,我们可以在面板中使用 class .table.假设有个 <div> 包含 .panel-body,我们可以向表格的顶部添加额外的边框用来分 ...

  7. shell脚本,awk在需要的行上打打印空行。

    注解: 判断每行中是否包含字母a,包含了,就将$1的值赋值给变量a,然后判断变量a是否存在,存在打印一个空行,在将变量的值使用空变量b赋值,最后在打印输出. 结果就是在包含有字符a的行上打印一个空行.

  8. 第四次作业:Windows各种基本应用的命令处理方法

    删除文件夹命令? rd (remove directory) 如何给文件夹重新命名? ren (rename) 如何在文件夹中建立文件夹? md swift\a 如何用命令查看文本文件的内容? typ ...

  9. cocostudio的bug(1)

    今天有个女同事问我一个问题,两个cocostudio的ui同时addChild到一个layer上面,高层级的ui设置visible为false,低层级的ui设置的visible设置为true,然后低层 ...

  10. Java 的Throwable、error、exception的区别

    1. 什么是异常? 异常本质上是程序上的错误,包括程序逻辑错误和系统错误.比如使用空的引用(NullPointerException).数组下标越界(IndexOutOfBoundsException ...