这应该暂时是个终结篇了...

最后在这里讨论LCT的一个常用操作:维护虚子树信息

这也是一个常用操作

下面我们看一下如何来维护

以下内容转自https://blog.csdn.net/neither_nor/article/details/52979425

对于一个点x,如果我们对x进行access操作,那么他的虚子树内将包含且仅包含他原树中子树内除了他自己以外的所有点,这时如果我们维护了他的虚子树信息和,我们把这个信息与他自己的信息合并,我们就得到了他在原树中的子树信息

在下面的讨论中,我们发现我们可以同时维护一个点的虚子树信息和LCT子树信息来达到维护虚子树信息的目的

考虑一个点的虚子树信息会在什么情况下发生改变,一个点的虚子树信息改变,当且仅当进行link或者access操作时。

在进行access操作时,我们会有更换一个点的x右儿子的操作,这时我们要把x原来的右儿子的LCT子树信息加入x的虚子树信息,把x的新的右儿子的LCT子树信息从x的虚子树信息中减去

在进行link操作时,我们会先把点x换根,然后连一条x到y的虚边,这时我们发现不仅y的虚子树信息需要加入x的LCT子树信息,y的所有祖先的LCT子树信息也需要更改,而这样我们就没法维护了,所以在进行link操作的时候我们需要把y也换根(其实access再splay就行了,不用换成根),这样就只会对y的虚子树信息和LCT子树信息产生影响

我们还需要维护一个x的LCT子树的信息和,x的LCT子树的信息和就等于x的实儿子的LCT子树信息和加上x的虚子树的信息和加上x自己,在splay的update函数中就可以直接维护

这样我们就完成了对子树信息的维护

换根操作、cut操作和链修改操作并不影响我们上边的讨论,所以也是兹磁的

转载结束

例:bzoj 4530大融合

#include <cstdio>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <queue>
#include <stack>
using namespace std;
int c[100005][2];
int f[100005];
bool ttag[100005];
int si[100005];
int s[100005];
void update(int rt)
{
s[rt]=s[c[rt][0]]+s[c[rt][1]]+si[rt]+1;
}
bool berot(int rt)
{
if(c[f[rt]][0]==rt||c[f[rt]][1]==rt)
{
return 0;
}
return 1;
}
void reverse(int rt)
{
swap(c[rt][0],c[rt][1]);
ttag[rt]^=1;
}
void pushdown(int rt)
{
if(ttag[rt])
{
if(c[rt][0])
{
reverse(c[rt][0]);
}
if(c[rt][1])
{
reverse(c[rt][1]);
}
ttag[rt]=0;
}
}
void repush(int rt)
{
if(!berot(rt))
{
repush(f[rt]);
}
pushdown(rt);
}
void rotate(int rt)
{
int ltyp=0;
int fa=f[rt];
int ffa=f[fa];
if(c[fa][1]==rt)
{
ltyp=1;
}
if(!berot(fa))
{
if(c[ffa][0]==fa)
{
c[ffa][0]=rt;
}else
{
c[ffa][1]=rt;
}
}
c[fa][ltyp]=c[rt][ltyp^1];
c[rt][ltyp^1]=fa;
f[c[fa][ltyp]]=fa;
f[fa]=rt;
f[rt]=ffa;
update(fa);
}
void splay(int rt)
{
repush(rt);
while(!berot(rt))
{
int fa=f[rt];
int ffa=f[fa];
int jr=f[ffa];
if(!berot(fa))
{
if((c[fa][0]==rt&&c[ffa][0]!=fa)||(c[fa][1]==rt&&c[ffa][1]!=fa))
{
rotate(rt);
}else
{
rotate(fa);
}
}
rotate(rt);
}
update(rt);
}
void access(int rt)
{
int y=0;
while(rt)
{
splay(rt);
si[rt]+=s[c[rt][1]];
c[rt][1]=y;
si[rt]-=s[c[rt][1]];
update(rt);
y=rt;
rt=f[rt];
}
}
void makeroot(int rt)
{
access(rt);
splay(rt);
reverse(rt);
}
void split(int st,int ed)
{
makeroot(st);
access(ed);
splay(ed);
}
void link(int st,int ed)
{
split(st,ed);
f[st]=ed;
si[ed]+=s[st];
update(ed);
} inline int read()
{
int f=1,x=0;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int n,q;
char ss[5];
int main()
{
scanf("%d%d",&n,&q);
for(int i=1;i<=n;i++)
{
s[i]=1;
}
while(q--)
{
scanf("%s",ss);
int x=read(),y=read();
if(ss[0]=='A')
{
link(x,y);
}else
{
split(x,y);
printf("%lld\n",(long long)(si[x]+1)*(long long)(si[y]+1));
}
}
return 0;
}

例:bzoj 3510首都

#include <cstdio>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <queue>
#include <stack>
using namespace std;
int c[100005][2];
int f[100005];
int ff[100005];
int s[100005];
int si[100005];
bool ttag[100005];
int tot=0;
int findf(int x)
{
if(x==ff[x])
{
return x;
}
return ff[x]=findf(ff[x]);
}
void update(int rt)
{
s[rt]=s[c[rt][0]]+s[c[rt][1]]+si[rt]+1;
}
bool berot(int rt)
{
if(c[f[rt]][0]==rt||c[f[rt]][1]==rt)
{
return 0;
}
return 1;
}
void reverse(int rt)
{
swap(c[rt][0],c[rt][1]);
ttag[rt]^=1;
}
void pushdown(int rt)
{
if(ttag[rt])
{
reverse(c[rt][0]);
reverse(c[rt][1]);
ttag[rt]=0;
}
}
void repush(int rt)
{
if(!berot(rt))
{
repush(f[rt]);
}
pushdown(rt);
}
void rotate(int rt)
{
int ltyp=0;
int fa=f[rt];
int ffa=f[fa];
if(c[fa][1]==rt)
{
ltyp=1;
}
if(!berot(fa))
{
if(c[ffa][1]==fa)
{
c[ffa][1]=rt;
}else
{
c[ffa][0]=rt;
}
}
c[fa][ltyp]=c[rt][ltyp^1];
c[rt][ltyp^1]=fa;
f[c[fa][ltyp]]=fa;
f[fa]=rt;
f[rt]=ffa;
update(fa);
}
void splay(int rt)
{
repush(rt);
while(!berot(rt))
{
int fa=f[rt];
int ffa=f[fa];
if(!berot(fa))
{
if((c[fa][0]==rt&&c[ffa][0]!=fa)||(c[fa][1]==rt&&c[ffa][1]!=fa))
{
rotate(rt);
}else
{
rotate(fa);
}
}
rotate(rt);
}
update(rt);
}
void access(int rt)
{
int y=0;
while(rt)
{
splay(rt);
si[rt]+=s[c[rt][1]];
c[rt][1]=y;
si[rt]-=s[c[rt][1]];
update(rt);
y=rt;
rt=f[rt];
}
}
void makeroot(int rt)
{
access(rt);
splay(rt);
reverse(rt);
}
void split(int st,int ed)
{
makeroot(st);
access(ed);
splay(ed);
}
void link(int st,int ed)
{
split(st,ed);
f[st]=ed;
si[ed]+=s[st];
update(ed);
}
int query(int rt)
{
int ls=0,rs=0,ltemp=0,rtemp=0;
int ed=s[rt]>>1;
bool flag=s[rt]%2;
int ret=0x3f3f3f3f;
while(rt)
{
pushdown(rt);
int lc=c[rt][0];
int rc=c[rt][1];
ltemp=ls+s[lc];
rtemp=rs+s[rc];
if(ltemp<=ed&&rtemp<=ed)
{
if(flag)
{
ret=rt;
break;
}else if(rt<ret)
{
ret=rt;
}
}
if(ltemp<rtemp)
{
ls+=s[lc]+si[rt]+1;
rt=rc;
}else
{
rs+=s[rc]+si[rt]+1;
rt=lc;
}
}
splay(ret);
return ret;
}
inline int read()
{
int f=1,x=0;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int n,m;
char ss[10];
int main()
{
n=read(),m=read();
for(int i=1;i<=n;i++)
{
tot^=i;
s[i]=1;
ff[i]=i;
}
while(m--)
{
scanf("%s",ss);
if(ss[0]=='A')
{
int x=read(),y=read();
link(x,y);
int f1=findf(x);
int f2=findf(y);
split(f1,f2);
int rf=query(f2);
tot=tot^f1^f2^rf;
ff[f1]=ff[f2]=ff[rf]=rf;
}else if(ss[0]=='Q')
{
int x=read();
printf("%d\n",findf(x));
}else
{
printf("%d\n",tot);
}
}
return 0;
}

SPLAY,LCT学习笔记(六)的更多相关文章

  1. LCT 学习笔记

    LCT学习笔记 前言 自己定的学习计划看起来完不成了(两天没学东西,全在补题),决定赶快学点东西 于是就学LCT了 简介 Link/Cut Tree是一种数据结构,我们用它解决动态树问题 但是LCT不 ...

  2. java之jvm学习笔记六-十二(实践写自己的安全管理器)(jar包的代码认证和签名) (实践对jar包的代码签名) (策略文件)(策略和保护域) (访问控制器) (访问控制器的栈校验机制) (jvm基本结构)

    java之jvm学习笔记六(实践写自己的安全管理器) 安全管理器SecurityManager里设计的内容实在是非常的庞大,它的核心方法就是checkPerssiom这个方法里又调用 AccessCo ...

  3. Learning ROS for Robotics Programming Second Edition学习笔记(六) indigo xtion pro live

    中文译著已经出版,详情请参考:http://blog.csdn.net/ZhangRelay/article/category/6506865 Learning ROS for Robotics Pr ...

  4. Typescript 学习笔记六:接口

    中文网:https://www.tslang.cn/ 官网:http://www.typescriptlang.org/ 目录: Typescript 学习笔记一:介绍.安装.编译 Typescrip ...

  5. python3.4学习笔记(六) 常用快捷键使用技巧,持续更新

    python3.4学习笔记(六) 常用快捷键使用技巧,持续更新 安装IDLE后鼠标右键点击*.py 文件,可以看到Edit with IDLE 选择这个可以直接打开编辑器.IDLE默认不能显示行号,使 ...

  6. Go语言学习笔记六: 循环语句

    Go语言学习笔记六: 循环语句 今天学了一个格式化代码的命令:gofmt -w chapter6.go for循环 for循环有3种形式: for init; condition; increment ...

  7. 【opencv学习笔记六】图像的ROI区域选择与复制

    图像的数据量还是比较大的,对整张图片进行处理会影响我们的处理效率,因此常常只对图像中我们需要的部分进行处理,也就是感兴趣区域ROI.今天我们来看一下如何设置图像的感兴趣区域ROI.以及对ROI区域图像 ...

  8. Linux学习笔记(六) 进程管理

    1.进程基础 当输入一个命令时,shell 会同时启动一个进程,这种任务与进程分离的方式是 Linux 系统上重要的概念 每个执行的任务都称为进程,在每个进程启动时,系统都会给它指定一个唯一的 ID, ...

  9. # go微服务框架kratos学习笔记六(kratos 服务发现 discovery)

    目录 go微服务框架kratos学习笔记六(kratos 服务发现 discovery) http api register 服务注册 fetch 获取实例 fetchs 批量获取实例 polls 批 ...

  10. Spring Boot 学习笔记(六) 整合 RESTful 参数传递

    Spring Boot 学习笔记 源码地址 Spring Boot 学习笔记(一) hello world Spring Boot 学习笔记(二) 整合 log4j2 Spring Boot 学习笔记 ...

随机推荐

  1. Math对象小笔记

    来,总结下Math对象的常用方法和属性 1.E  自然对数的底数 Math.E; //2.718281828459045 2.PI 圆周率 Math.PI; //3.141592653589793 3 ...

  2. excel多元回归-系数参数解读

    sklearn实战-乳腺癌细胞数据挖掘 https://study.163.com/course/introduction.htm?courseId=1005269003&utm_campai ...

  3. 获取天气预报API

    sklearn实战-乳腺癌细胞数据挖掘(博主亲自录制视频) https://study.163.com/course/introduction.htm?courseId=1005269003& ...

  4. 一张图看懂JavaScript中数组的迭代方法:forEach、map、filter、reduce、every、some

    好吧,竟然不能单发一张图,不够200字啊不够200字! 在<JavaScript高级程序设计>中,分门别类介绍了非常多数组方法,其中迭代方法里面有6种,这6种方法在实际项目有着非常广泛的作 ...

  5. PHP 进行支付宝开发中return_url和notify_url的区别分析

    在支付宝处理业务中return_url,notify_url是返回些什么状态呢,我们要根据它来做一些处理就必须了解return_url,notify_url的区别,下面我就来给大家介绍; 一.问题描述 ...

  6. java中import机制(指定import和import *的区别)

    转自:https://www.cnblogs.com/dtts/p/4692480.html java中有两种包的导入机制,总结如下: 单类型导入(single-type-import),       ...

  7. MyBatis参数传递

    一.单个参数: public List<XXBean> getXXBeanList(String xxCode); <select id="getXXXBeanList&q ...

  8. 16. Spring boot 错误页面

      默认效果:1).浏览器,返回一个默认的错误页面 1.1 请求头 1.2返回结果 2).如果是其他客户端,默认响应一个json数据 2.1请求头 2.2返回结果 { "timestamp& ...

  9. 集大软件工程15级个人作业Week1

    集大软件工程15级个人作业Week1 孙志威 201521123077 博客园主页 码云地址 阅读参考材料,并回答下面几个问题 (1)回想一下你初入大学时对网络工程专业的畅想 当初你是如何做出选择网络 ...

  10. java程序运存扩容

    线上程序随着业务增多,运行的越来越慢,初步判定是因为内存分配的太小导致频繁的进行GC和OOM,于是着手增加内存上限. 增加内存上限都知道是修改java启动的opt,因为服务容器是tomcat 首先是在 ...