首页 > 其他分享 >动态树笔记

动态树笔记

时间:2024-08-22 11:07:47浏览次数:12  
标签:LCT 子树 int text 笔记 son 修改 动态

不知道“树链剖分”、“全局平衡二叉树”等应不应该归类到“动态树”里面...

解决动态树问题的本质是将原树映射到一个高度为 \(O(\log n)\) 的树上。

树链剖分

主要是重链剖分,具体略. 支持:

  • 链修改
  • 链查询
  • 子树修改
  • 子树查询

这里的修改、查询需要满足可以用数据结构维护.

一般两只 log.

LCT

全称 Link-Cut-Tree,拥有以下函数:

  • \(\text{get}\), \(\text{nrt}\), \(\text{up}\), \(\text{upd}\), \(\text{down}\), \(\text{rot}\)
  • \(\text{splay}\)
  • \(\text{access}\)
  • \(\text{makert}\)
  • \(\text{link}\), \(\text{cut}\), \(\text{split}\), \(\text{find}\)

具体略.

支持:

  • 链修改
  • 链查询
  • 连边、断边
  • 判断连通
  • 子树查询可减信息

一只 log

全局平衡二叉树

重链剖分,每条链像 LCT 一样维护成一棵二叉树,如此建树:

记每个点的权值为轻子树大小之和 + 1,求出链的加权中点作为根,然后递归建树.(加权中点:左边之和与右边之和的差最小)

跳轻边,最多 \(\log n\) 次;跳树边,轻儿子 size 翻倍,故总树高 \(O(\log n)\).

链修改、链查询可拆为二叉树上子树修改、子树查询

子树修改、子树查询等可维护轻儿子的信息、标记

支持:

  • 链修改
  • 链查询
  • 子树修改
  • 子树查询

可爱的单 log 噢

ETT

全称 Euler Tour Tree,通过维护欧拉遍历序来维护树

欧拉遍历序(ETR):维护一个序列,DFS 时每访问到一个点或一条有向边就加入序列. 这样序列长度为 \(3n-2\).

因为是维护序列,所以用任意平衡树都可以

加入点的目的是存储点上的信息,这在 ETR 上可以理解为加入自环

这个序列本身就是一个环

  • 换根

Picture 1

找到自环 \((v,v)\) 的位置,断开成两段,序列顺序由“蓝、黄”变成“黄、蓝”。

  • 加边

Picture 2

让 \(u,v\) 变成根,然后让 \(v\) 作为 \(u\) 的儿子即可.

找到自环 \((u,u)\) 的位置,在后面插入绿 + 粉。

  • 删边

Picture 3

找到边 \((u,v),(v,u)\) 的位置,断成三段,蓝、黄合并

  • 路径和查询

需要信息具有可减性,这样你遍历完一个子树过后信息就变成 0 了,抵消掉了

设边权全为 1,假如询问 \(u\to v\) 的路径长度,把向下走的边看成 (,把向上走的边看成 )

取出 \(u\) 到 \(v\) 这一段的括号序列长度就是答案

信息的合并:括号序列一定形如 )))(((( 这样

两个括号序列合并,先拼接起来,再消去匹配的括号

若边权非 1,可以用同样的逻辑去做

  • 连通块修改 + 查询

显然转化为区间修改、区间查询


注意到 ETT 不好快速找到父亲和自己代表的子树,多用于维护无根树,支持:

  • 换根
  • 加边
  • 删边
  • 连通块的修改 / 查询
  • 询问路径长度

“换根”操作与“子树的修改 / 查询”是矛盾的,因为换根使得儿子的顺序混乱了

以下内容不保熟

如何改进?一种思路是维护 ETT 的同时维护一棵 LCT,LCT 只维护树的形态

可以维护一个性质:LCT 中 \(u\) 的实儿子作为 ETT 中的第一个儿子

考虑链修改:假如修改 \((u,v)\),先令 \(u\to v\) 这一段在 LCT 上是一段实链

然后发现 \(u\to v\) 这一段在 ETT 中是一段连续的区间!就可以修改了.

考虑换根:假如根由 \(u\to v\)

Picture 4

可以先 access(v),然后找到 \(v\) 的位置,考虑入栈序、出栈序

  • 换之前:\(\color{red}{u_1A_1B_1v_1}\ \color{green}{FGv_2EB_2DA_2Cu_2}\)
  • 换之后:\(\color{red}{v_1B_1A_1u_1}\ \color{green}{Cu_2DA_2EB_2FGv_2}\)

找到 \(v_1\) 的位置 \(p\),前后分别在 LCT 上打翻转标记即可,标记的应用写起来比较复杂

不保熟内容结束

但是谁写呢 ╮(╯▽╰)╭

UPD:还真有人写

加上不保熟内容,他就可以做 Sone 1 了,但是双 log 常数大的要命还难写 QAQ

AAAT

这部分参考了这篇博客

其实就是魔改版 LCT,思路比较简单

注意到在 LCT 里面我们想要维护虚子树所有信息

那么考虑直接用平衡树维护一个点所有虚儿子

因为虚儿子之间并无先后顺序可言,且为了保证复杂度能均摊,我们采用 Leafy Splay 维护,易知点数仍然 \(O(n)\)

如图(懒得画图了,采用神 Claris 的图片):

Picture 6

对于下面这棵以 1 为根的树

Picture 7

在 AAA 树中是这样维护的

Picture 8


考虑一些基本函数与实现

每个点有 son[0],son[1] 表示实链 Splay 的两个儿子,son[2],son[3] 表示虚边 Splay 的两个儿子

  • \(\text{Add}(x,y)\) 操作:在 \(x\) 的虚子树内新增点 \(y\),必要的话新增内部白点.
  • \(\text{Del}(x)\) 操作:把 \(x\) 与他父亲之间的虚边断开,必要的话删除没用的内部白点.
  • \(\text{Access}(x)\) 操作:把 \(x\) 到根路径上的所有边变成实边,并把 \(x\) 向他所有儿子的边变成虚边.

考虑普通 LCT 的 Access 过程:

void access(int x) {
    for (int y = 0; x; y = x, x = fa[x]) {
        splay(x);
        son[x][1] = y;
        up(x);
    }
}

每一步都是实虚边的转化,有了 \(\text{Add}\) 和 \(\text{Del}\) 操作,可以很自然的改写成:

void access(int x) {
    for (int y = 0; x; y = x, x = fa[x]) {
        splay(x);
        del(y);
        add(x, son[x][1]);
        setson(x, 1, y);
        up(x);
    }
}
  • \(\text{Makeroot}(x)\) 操作:与 LCT 一致,注意只交换 son[0]son[1].
  • \(\text{Link}(x, y)\) 操作:

考虑普通 LCT 的 Link 过程:

void link(int x, int y) {
    makeroot(x);
    splay(x);
    f[x] = y;
}

可以很自然的改写成:

void link(int x, int y) {
    makeroot(x);
    splay(x);
    add(y, x);
}
  • \(\text{Cut}\) 操作:与 LCT 一致.
  • \(\text{Split}\) 操作:与 LCT 一致.
  • 子树操作:

方便起见首先 \(\text{Access}(x)\),这样 \(x\) 向它的孩子连着的肯定都是虚边,\(x\) 的子树部分就是 \(x\) 的虚边 Splay。

void changetree(int x, tag p) {
    access(x);
    splay(x);
    val[x] = atag(val[x], p);
    for (int i = 2; i < 4; i++)
        if(son[x][i]) tagtree(son[x][i], p, 1);
    up(x);
    splay(x);
}
data asktree(int x) {
    access(x);
    splay(x);
    data t = data(val[x]);
    for (int i = 2; i < 4; i++)
        if (son[x][i]) t = t + asum[son[x][i]];
    return t;
}

做完了,可以证明是单 log 的。

他可以做 Sone 1,讲一下维护方式:

一个点总共维护的信息有:

  • \(\text{in}\):这个点是否为内部白点
  • \(\text{val}\):这个点的点权
  • \(\text{csum}\):链上信息和
  • \(\text{tsum}\):子树信息和(不包括链上)
  • \(\text{asum}\):所有信息和
csum[x] = val[x] + csum[son[x][0]] + csum[son[x][1]];
tsum[x] = tsum[son[x][0]] + tsum[son[x][1]] + asum[son[x][2]] + asum[son[x][3]];
asum[x] = csum[x] + tsum[x]

维护的标记有:

  • \(\text{rev}\):翻转标记
  • \(\text{ctag}\):链修改标记
  • \(\text{ttag}\):子树修改标记(不包括链上)

\(\text{ttag}\) 的下传方法:

  • 如果是在实链中的下传,直接下传到 \(\text{ttag}\),无需修改。
  • 如果是虚边 Splay 中下传到内部点,下传到 \(\text{ttag}\) 并修改。
  • 如果是虚边 Splay 中下传到外部点,下传到 \(\text{ttag}\) 和 \(\text{ctag}\) 并修改。

同时还需要做内存回收。然后做完了。

SATT

压轴内容,喜闻乐见

很可惜的是,他被安排到了我的另一篇文章

~~ 完结撒花 ~~

标签:LCT,子树,int,text,笔记,son,修改,动态
From: https://www.cnblogs.com/laijinyi/p/18373384/dynamic-trees

相关文章

  • GPT4SM论文阅读笔记
    AreGPTEmbeddingsUsefulforAdsandRecommendation?论文阅读笔记Abstract现存的问题:​ 尽管LLMs潜力巨大,但关于其文本嵌入是否能帮助广告和推荐服务的讨论却十分有限。提出方法:​ 为了探索GPT嵌入在广告和推荐中的应用,我们提出了三种策略,将LLMs的知识整合到基本P......
  • Linux系统运维笔记,openEuler-22.03 安装阿里(aliyun)yum
    Linux系统运维笔记,openEuler-22.03 安装阿里(aliyun)yum阿里巴巴开源镜像站点:http://mirrors.aliyun.com yum源理解yum源仓库的地址在/etc/yum.repos.d/,并且只能读出第一层的repo文件,yum仓库的文件都是以.repo结尾的。为加快yum下载,我们下载阿里云的.repo仓库文件,放到/e......
  • DP斜率优化学习笔记
    最后一次修改:2024.7.1614:39P.MBy哈哈铭简介“斜率优化”顾名思义就是用斜率进行优化,让\(DP\)的时间复杂度更优。一般情况下,将动态转移方程化简后得到这样的关系式:\[\frac{y_1-y_2}{x_1-x_2}\leqK\]然后通过该式进行转移,以达到优化时间复杂度的目的。小tip:推公式前......
  • 算法笔记|Day32动态规划V
    算法笔记|Day32动态规划V※※※※※完全背包问题理论基本题目描述题目分析采用一维数组(滚动数组)☆☆☆☆☆leetcode518.零钱兑换II题目分析代码☆☆☆☆☆leetcode377.组合总和Ⅳ题目分析代码☆☆☆☆☆KamaCoder57.爬楼梯(待补充)题目分析代码※※※※※完全......
  • Spark超全笔记 一站式搞定!!
    sparkSparkSpark和Hadoop的区别Spark计算流程Spark组成架构(spark的五大组件)Spark内核调度流程Spark并行度RDDRDD的五大特性RDD的创建RDD常用算子常用transformation算子常用action算子RDD缓存和checkpoint对比RDD依赖依赖管理DAG有向无环图为什么要进行stage划分Spar......
  • 【学习笔记】数学基础:Ferrers 图
    在分拆时我们有的时候很难搞,所以需要引入Ferrers图定义将分拆的每个部分用点组成的行表示,每行点的个数是这个部分的大小根据分拆的定义,Ferrers图中不同的行按照递减的顺序排放分拆:将自然数n写成递降正整数和的表示。\[n=r_1+r_2+\ldots+r_k\quadr_1\ger_2\ge\ldo......
  • C语言实现通讯录-动态版本与文件版本
    C语言实现通讯录-动态版本与文件版本1.前言2.动态版本2.1联系人信息之前的:改版:2.2初始化之前的:改版:2.3自动扩容3.文件版本3.1自动保存函数实现:效果:3.2打开时加载信息函数实现:效果:1.前言在先前的探索中,我构建了一个C语言实现简单的通讯录,它能够存储一定数量的......
  • BufferQueue的试用笔记
    简介BufferQueue是一个用.NET编写的高性能的缓冲队列实现,支持多线程并发操作。源码网站:https://github.com/eventhorizon-cli/BufferQueue功能设计支持创建多个Topic,每个Topic可以有多种数据类型。每一对Topic和数据类型对应一个独立的缓冲区。支持创建多个Cons......
  • 动态规划(一)
    动态规划(一)多阶段决策问题动态规划是运筹学的一个分支,是求解多阶段决策过程最优化问题的数学方法。动态规划在经济管理、工程技术、工农业生产及军事部门中都有着广泛的应用,并且获得了显著的效果。学习动态规划,我们首先要了解多阶段决策问题。最短路径问题:背包问......
  • mini-lsm通关笔记Week1Day4
    项目地址:https://github.com/skyzh/mini-lsm个人实现地址:https://gitee.com/cnyuyang/mini-lsmTask1-SSTBuilder在此任务中,您需要修改:src/table/builder.rssrc/table.rsSST由存储在磁盘上的数据块和索引块组成。通常,数据块都是懒加载的-直到用户发出请求,它们才会被加载......