LCT(Link-Cut Tree)
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)的更多相关文章
- LCT(Link Cut Tree)总结
概念.性质简述 首先介绍一下链剖分的概念链剖分,是指一类对树的边进行轻重划分的操作,这样做的目的是为了减少某些链上的修改.查询等操作的复杂度.目前总共有三类:重链剖分,实链剖分和并不常见的长链剖分. ...
- FOJ题目Problem 2082 过路费 (link cut tree边权更新)
Problem 2082 过路费 Accept: 382 Submit: 1279 Time Limit: 1000 mSec Memory Limit : 32768 KB Proble ...
- bzoj 3282: Tree (Link Cut Tree)
链接:https://www.lydsy.com/JudgeOnline/problem.php?id=3282 题面: 3282: Tree Time Limit: 30 Sec Memory L ...
- HDOJ 题目2475 Box(link cut tree去点找祖先)
Box Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Submi ...
- POJ 题目3237 Tree(Link Cut Tree边权变相反数,求两点最大值)
Tree Time Limit: 5000MS Memory Limit: 131072K Total Submissions: 6131 Accepted: 1682 Description ...
- BZOJ 题目1036: [ZJOI2008]树的统计Count(Link Cut Tree,改动点权求两个最大值和最大值)
1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec Memory Limit: 162 MB Submit: 8421 Solved: 3439 [Submi ...
- 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 ...
- LCT总结——概念篇+洛谷P3690[模板]Link Cut Tree(动态树)(LCT,Splay)
为了优化体验(其实是强迫症),蒟蒻把总结拆成了两篇,方便不同学习阶段的Dalao们切换. LCT总结--应用篇戳这里 概念.性质简述 首先介绍一下链剖分的概念(感谢laofu的讲课) 链剖分,是指一类 ...
- LuoguP3690 【模板】Link Cut Tree (动态树) LCT模板
P3690 [模板]Link Cut Tree (动态树) 题目背景 动态树 题目描述 给定n个点以及每个点的权值,要你处理接下来的m个操作.操作有4种.操作从0到3编号.点从1到n编号. 0:后接两 ...
- P3690 【模板】Link Cut Tree (动态树)
P3690 [模板]Link Cut Tree (动态树) 认父不认子的lct 注意:不 要 把 $fa[x]$和$nrt(x)$ 混 在 一 起 ! #include<cstdio> v ...
随机推荐
- dp cf 1700 最近几天的刷题
C. Number of Ways 这个题目的意思是,把这个n的序列分成三个连续的部分,要求这三个部分的和是一样的.问这种划分的方法有多少种. 这个题目和之前写过的数字划分有点像,这个就是要先进行前缀 ...
- 2407: C语言习题 整数转换成字符串
2407: C语言习题 整数转换成字符串 Time Limit: 1 Sec Memory Limit: 128 MBSubmit: 917 Solved: 416[Submit][Status] ...
- python_82_标准库_random模块
import random print(help(random.random)) #随机整数 print(random.randint(1,7))#生成一个[1, 7]的随机整数 print(rand ...
- PAT (Basic Level) Practise (中文)-1039. 到底买不买(20)
PAT (Basic Level) Practise (中文)-1039. 到底买不买(20) http://www.patest.cn/contests/pat-b-practise/1039 小红 ...
- C# 使用Epplus导出Excel [4]:合并指定行
C# 使用Epplus导出Excel [1]:导出固定列数据 C# 使用Epplus导出Excel [2]:导出动态列数据 C# 使用Epplus导出Excel [3]:合并列连续相同数据 C# 使用 ...
- 关于C与C++的区别
笔者介绍:姜雪伟,IT公司技术合伙人,IT高级讲师,CSDN社区专家,特邀编辑,畅销书作者,已出版书籍:<手把手教你架构3D游戏引擎>电子工业出版社和<Unity3D实战核心技术详解 ...
- gradle更换国内镜像、配置本地仓库地址
gradle更换国内镜像,安装包解压后init.d文件夹下面创建init.gradle文件,内容如下 allprojects{ repositories { def REPOSITORY_URL = ...
- 洛谷 P5015 标题统计
第一道题很简单,标签:字符串.模拟. 只需要一个判断去除空格就对了: if(a[i]!=' ' && a[i]!='\n') v++; code: #include<iostre ...
- 洛谷P3372线段树1
难以平复鸡冻的心情,虽然可能在大佬眼里这是水题,但对蒟蒻的我来说这是个巨大的突破(谢谢我最亲爱的lp陪我写完,给我力量).网上关于线段树的题解都很玄学,包括李煜东的<算法竞赛进阶指南>中的 ...
- 【数学 BSGS】bzoj2242: [SDOI2011]计算器
数论的板子集合…… Description 你被要求设计一个计算器完成以下三项任务: 1.给定y,z,p,计算Y^Z Mod P 的值: 2.给定y,z,p,计算满足xy≡ Z ( mod P )的最 ...