SPLAY,LCT学习笔记(六)
这应该暂时是个终结篇了...
最后在这里讨论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学习笔记(六)的更多相关文章
- LCT 学习笔记
LCT学习笔记 前言 自己定的学习计划看起来完不成了(两天没学东西,全在补题),决定赶快学点东西 于是就学LCT了 简介 Link/Cut Tree是一种数据结构,我们用它解决动态树问题 但是LCT不 ...
- java之jvm学习笔记六-十二(实践写自己的安全管理器)(jar包的代码认证和签名) (实践对jar包的代码签名) (策略文件)(策略和保护域) (访问控制器) (访问控制器的栈校验机制) (jvm基本结构)
java之jvm学习笔记六(实践写自己的安全管理器) 安全管理器SecurityManager里设计的内容实在是非常的庞大,它的核心方法就是checkPerssiom这个方法里又调用 AccessCo ...
- Learning ROS for Robotics Programming Second Edition学习笔记(六) indigo xtion pro live
中文译著已经出版,详情请参考:http://blog.csdn.net/ZhangRelay/article/category/6506865 Learning ROS for Robotics Pr ...
- Typescript 学习笔记六:接口
中文网:https://www.tslang.cn/ 官网:http://www.typescriptlang.org/ 目录: Typescript 学习笔记一:介绍.安装.编译 Typescrip ...
- python3.4学习笔记(六) 常用快捷键使用技巧,持续更新
python3.4学习笔记(六) 常用快捷键使用技巧,持续更新 安装IDLE后鼠标右键点击*.py 文件,可以看到Edit with IDLE 选择这个可以直接打开编辑器.IDLE默认不能显示行号,使 ...
- Go语言学习笔记六: 循环语句
Go语言学习笔记六: 循环语句 今天学了一个格式化代码的命令:gofmt -w chapter6.go for循环 for循环有3种形式: for init; condition; increment ...
- 【opencv学习笔记六】图像的ROI区域选择与复制
图像的数据量还是比较大的,对整张图片进行处理会影响我们的处理效率,因此常常只对图像中我们需要的部分进行处理,也就是感兴趣区域ROI.今天我们来看一下如何设置图像的感兴趣区域ROI.以及对ROI区域图像 ...
- Linux学习笔记(六) 进程管理
1.进程基础 当输入一个命令时,shell 会同时启动一个进程,这种任务与进程分离的方式是 Linux 系统上重要的概念 每个执行的任务都称为进程,在每个进程启动时,系统都会给它指定一个唯一的 ID, ...
- # go微服务框架kratos学习笔记六(kratos 服务发现 discovery)
目录 go微服务框架kratos学习笔记六(kratos 服务发现 discovery) http api register 服务注册 fetch 获取实例 fetchs 批量获取实例 polls 批 ...
- Spring Boot 学习笔记(六) 整合 RESTful 参数传递
Spring Boot 学习笔记 源码地址 Spring Boot 学习笔记(一) hello world Spring Boot 学习笔记(二) 整合 log4j2 Spring Boot 学习笔记 ...
随机推荐
- memcache、redis原理对比
一.问题: 数据库表数据量极大(千万条),要求让服务器更加快速地响应用户的需求. 二.解决方案: 1.通过高速服务器Cache缓存数据库数据 2.内存数据库 ( ...
- Python基础【day03】:入门知识拾遗(八)
本节内容 1.作用域 2.三元运算 3.进制 一.作用域 对于变量的作用域,执行声明并在内存中存在,该变量就可以在下面的代码中使用. 1 2 3 if 1==1: name = 'wupeiq ...
- 关于js事件执行顺序小技巧
js事件执行顺序是js中一个老生常谈的一个话题, 聊这个话题之前我们先谈谈怎么给页面元素绑定我们需要的事件 1.给页面元素绑定事件 a)直接在元素上面加上需要绑定的事件,如 <button ty ...
- POJ - 1850 Code(组合数学)
https://vjudge.net/problem/POJ-1850 题意 输出某字符串在字典中的位置.字符串不合规则时输出0. 分析 首先判断字符串合法性,也就是判断是不是升序排列的.如果符合,以 ...
- Python基础-day03
写在前面 上课第三天,打卡: 不要让干净的灵魂染上尘埃,永远年轻.永远热泪盈眶 一.再谈编码 - 文件的概念 '文件' 是一个抽象的概念,是操作系统提供的外部存储设备的抽象,对应底层的硬盘:它是程序 ...
- JavaScript之函数调用与被调用的上下文对象this
不同的调用机制决定了函数上下文对象的不同: 1. 作为普通函数进行调用时,其上下文是全局对象window; 2. 作为(对象)方法进行调用时,其上下文对象时拥有该方法的对象; 3. 作为构造器( ...
- 原生JS给元素添加class属性
有下面这三种简单语句. document.getElementsByTagName('body')[0].className = 'snow-container'; //设置为新的 document ...
- ROS安装与卸载
1 版本选择 ROS 虽说也叫操作系统,但它是寄生在 LINUX 操作系统之下的,所以要求大兄弟你的电脑里至少要先有一个 LINUX 操作系统. 而对 ROS 兼容性最好的当属 Ubuntu 操作系统 ...
- 如何将SVN仓库转换为Git仓库
按如下步骤操作就可以将SVN仓库完整的转换为Git仓库: 1) 将远程SVN仓库搬到本地(这一步主要是为了提高转换的速度,也可以忽略) 参考这篇文章: http://rongjih.blog. ...
- Win10 + Visual Studio 2017 下 OpenCV无法显示图像的问题
测试代码如下: #include "stdafx.h" #include<opencv2\opencv.hpp> #include<opencv2\highgui ...