link-cut tree
我曾经说过这么一句话: 要不是为了学LCT,我这辈子都不会学splay。
现在好了,splay学的差不多,开始学LCT时:
第一眼:什么鬼
第二眼:爆炸
第三眼:不会
第四眼:题解曰:“因为要维护动态链表,所以考虑平衡树维护,理论上splay和fhq treap都是可以的。”
理论上splay和fhq treap都是可以的
理论上splay和fhq treap都是可以的
理论上splay和fhq treap都是可以的
第五眼:不会
第无数眼:放弃
学习笔记-LCT篇·完
upd 2023.12.2
我—会—了一点点。
skr~
请看题:
【模板】动态树(LCT)
题目描述
给定
操作有四种,操作从
0 x y代表询问从x 到y 的路径上的点的权值的\text{xor} 和。保证x 到y 是联通的。1 x y代表连接x 到y ,若x 到y 已经联通则无需连接。2 x y代表删除边(x,y) ,不保证边(x,y) 存在。3 x y代表将点x 上的权值变成y 。
数据规模与约定
对于全部的测试点,保证:
-
- 对于操作
0, 1, 2 ,保证1 \leq x, y \leq n 。 - 对于操作
3 ,保证1 \leq x \leq n ,1 \leq y \leq 10^9 。
开始扯淡:
我们先抛开连边断边:
众所周知,静态树(这里指树的结构不会变化的树)的树链剖分大多数是重链剖分,它的中心思想是把树按照重轻边剖成若干条链(默认你会重链剖分,所以讲的粗略一点)。
而我们的LCT使用的叫做实链剖分,它用一种十分玄学的方式剖链,每次查询就把两点之间的路径变成一条链(这种链就叫实链),在变的过程中链维护链中需要的信息。变完之后链上的信息即为查询的答案。
那么链怎么变呢?
你在想什么?大声的说出来:
链表!
啊不是,噔
文艺平衡树!
对喽,就是文艺平衡树。我们可以用美丽如花的fhq-treap和丑如泥巴的splay。
为什么只能用它们??
Because they need to split and merge.(英语十级)
为什么要分裂合并?
Please look at 下文.(梅开二度)
我们用多个fhq-treap维护每一条链,并且每条链中序遍历下来每个点深度单调递增,并且对于每条链把fhq中排名为1的节点的成员变量.to设为原树中链顶的点的父亲,即虚边,并且fhq中每个节点维护成员变量.sum为fhq中此点子树中所有点点权的异或和。
假设树是这样的:
[图片]
每条链是这样的:
[图片]
连完父亲是这样的:
[图片]
基本的讲完了,接着讲主要的。
link(x,y)
接着上面的思路,要切断 那删你癌慕啊。
if(find(x)!=find(y))
return;
又来几个函数:
[图片]
那么我们先让
[图片]
那么只需要看删你癌慕直接return啊。
void cut(int x,int y)
{
if(find(x)!=find(y))//无边可删
return;
makeroot(x);
access(y);
access(x);
if(front(y)==y)//保证y是第一名,不然x和y中间还会有小三(bushi
to(y)=0;//切断关系
}
query(x,y)
求原树中
实现:
滑稽吧,这么简单还需要讲
首先让 .sum就好啦。
int query(int x,int y)
{
makeroot(x);
return tree[access(y)].sum;
}
update(x,val)
将点
滑稽吧
先让
void update(int x,int val)
{
makeroot(x);//x当根
access(x);//x与x成链,将x单独分离
tree[x].val=tree[x].sum=val;//直直直直直直直接修改
}
那么所有的操作我们就全部解决了ヽ(°▽゚)ノ
那么……
How do we write them:
莫得关系,逐一攻破:
NO.1 access(x)
作用前文讲过,这里不再赘述。
首先,定义一个空fhq,把每个处理完的链一个个合并,最后得到[维护(根到
得到伪代码:
int access(int cur)
{
int root=0;
从x开始跳链,保证x不跳到根节点的爸爸(0节点)
{
把链分成不比x低的链和比x低的链;
合并刚刚的链和root;
x=root所在树的排名为1的节点的.to,即原树中root所在树的排名为1的节点的爸爸;
}
return root;
}
即
[图片]
再次引进两个函数:
-
merge(x,y,z) -
split(x,y,z)