首页 > 编程语言 >【算法】LCT

【算法】LCT

时间:2024-02-05 09:02:57浏览次数:32  
标签:LCT 剖分 int 路径 splay 算法 节点

参考资料

前言

第一次学,感觉这玩意挺抽象……只能写下博客巩固一下印象。

概念

前置知识:树链剖分,Splay

给定一棵树,没有任何的更改操作,询问一些有关树上路径问题(如两点之间的权值和),就可以用树上倍增。而如果在此基础上增添了更改某个点的权值的操作,就需要用到树链剖分了。但是再加一个在保证仍然是一棵树的前提下,断开并连接一些边,就变成了动态树问题了。我们一般用 LCT 来求解动态树问题。

我们可以简单的把 LCT 理解成用一些 Splay 来维护动态的树链剖分,以期实现动态树上的区间操作。对于每条实链,我们建一个 Splay 来维护整个链区间的信息。 ——OI-Wiki

实链

这里出现了一个可能之前没见过的词——实链,它是链剖分的一种形式。为什么 LCT 不用重链剖分或者长链剖分?这是由于在 LCT 里面我们要能自由选择儿子,如果是重链剖分或者长链剖分,它的重儿子是所有儿子里面子树最长的或者深度最大的,没有给我们自由选择的权利。而实链剖分中我们可以自由选择哪些是实儿子,哪些是虚儿子。这种灵活可变性就是我们选择实链剖分的重要原因。

辅助树

辅助树可以理解为多个 splay 组成一个结构,其中每一个 splay 都维护了辅助树中的一条边。鉴于大多数情况下动态树问题可能维护的是一个森林,所以 LCT 实际上维护的是这些辅助树组成的森林。

关于辅助树的主要性质如下:

  1. 中序遍历每一个 splay 得到的序列对应原树中从上到下遍历的一条路径。也可以理解为中序遍历每一个 splay 得到的序列都是一段深度严格递增的序列。
  2. 每个节点都在且仅在一个 splay 里面出现
  3. 实链剖分的实边存在于 splay 里面,虚边是由一个 splay 的根节点指向该 splay 中序遍历最靠前的点在原树中的父亲。虚边和实边的区别在于虚边的儿子认父亲,而父亲不认儿子。

实现

重建重路径:access 函数

它的作用相当于重新建一条从 \(x\) 到根节点的实路径,即在同一棵 splay 里面。这个过程中可能会有一些边由虚变实,相应的也会有一些边由实变虚。

实现的方法是从下到上更新 splay,先将 \(x\) 转到当前这棵 splay 的根,这样方便进行之后的连边操作。这一操作导致需要更换 \(x\) 的实儿子以及更新 \(x\) 的信息。然后把 \(x\) 的父亲按照类似的方法转到它所在的 splay 的根,并将它的实儿子更换为 \(x\)。

void access(int x){
    for(int las=0;x;x=fa[x]){
        splay(x);
        tree[x].son[1]=las;
        pushup(x);
        las=x;
    }
}

换根:makeroot 函数

在维护路径信息的时候可能会出现路径深度无法严格递增的情况,这时候这条路径就完全不可能在同一个 splay 中,我们就需要将这条路径的一个端点在原树中换到根节点的位置,这样就能保证这条路径一定是严格递增的。

换根可以抽象理解为一条路径上的一些点的深度被更改了。我们先建出要求换成的节点 \(x\) 到根节点的一条实路径,即进行 access 操作。操作后的 \(x\) 一定和根节点在同一条实链上并且深度最深,导致再将 \(x\) 转上来之后它将没有右子树,所以将这棵 splay 翻转后会将它的左子树(即深度比它小的节点)都翻转到右子树(变成深度比它大的节点),这样 \(x\) 没有左子树就变成了深度最小的节点,成为了根节点。

void makeroot(int x){
    access(x);
    splay(x);
    addtag(x);
}

分割:split 函数

相当于把维护 \(x\) 到 \(y\) 路径的 splay 树给拿出来(但不是真的拿,也就是不是真的把边给断了拿出来)。直接把 \(x\) 换为根节点,再建一条从 \(y\) 到 \(x\) 的实路径,把 \(y\) 旋到根,这样它就在 splay 的最右边没有右儿子了。接着就可以很方便地访问 \(y\) 来获取路径信息。

void split(int x,int y){
    makeroot(x);
    access(y);
    splay(y);
}

找根:find 函数

将 \(x\) 和根节点重建出一条实链后,再把 \(x\) 旋上去。然后一直走它的左儿子,因为左儿子的深度会更小,沿路 pushdown 一下,最后按照 splay 的传统把查询到的点给旋上去。

int find(int x){
    access(x);
    splay(x);
    while(tree[x].son[0]){
        pushdown(x);
        x=tree[x].son[0];
    }
    splay(x);
    return x;
}

对于连边,首先需要判断需要连边的两个点 \(x\),\(y\) 是否在同一棵子树内,在的话显然不合法。然后将 \(x\) 给改成所在树的根,再将 \(x\) 的父亲改为 \(y\)。

对于断边,先把 \(x\) 改为根节点,然后判断 \(x\),\(y\) 是否有连边(即判断 \(x\),\(y\) 连通,\(x\),\(y\) 的路径上没有其他的链,\(y\) 没有右儿子),然后改一下 \(x\),\(y\) 的父亲儿子信息。

解释一下判断条件,第一条很显然,第二条可以通过判断 \(y\) 的父亲是不是 \(x\),\(x\) 的右儿子是不是 \(y\) 来解决,第三条需要满足的原因是如果 \(y\) 有右儿子,那么就会存在比 \(y\) 深度大但比 \(x\) 深度小的点,那么 \(x\),\(y\) 之前就不可能有直接的链相连。

void link(int x,int y){
    makeroot(x);
    if(find(y)==x) return;
    fa[x]=y;
}

void cut(int x,int y){
    makeroot(x);
    if(find(y)!=x||fa[y]!=x||tree[x].son[1]!=y||tree[y].son[1]) return;
    fa[y]=tree[x].son[1]=0;
    pushup(x);
}

由于 LCT 的每种操作时间复杂度基本基于 access 函数,而它的时间复杂度是 \(O(\log_2 n)\),那么每种操作的时间复杂度也是 \(O(\log_2 n)\)。

标签:LCT,剖分,int,路径,splay,算法,节点
From: https://www.cnblogs.com/Cloote/p/18004335

相关文章

  • 可控概率抽奖算法
    说明本文PHP语言去实现,只实现核心可控概率引擎,库存判断等其它业务需要其它代码配合实现。代码/***@function封装可控概率的抽奖功能*@param$arrarray数据集合*@param$weight_keystring权重字段*@returnarray被选中的元素*/funct......
  • R语言LASSO特征选择、决策树CART算法和CHAID算法电商网站购物行为预测分析
    全文链接:http://tecdat.cn/?p=32275原文出处:拓端数据部落公众号本文通过分析电子商务平台的用户购物行为,帮助客户构建了一个基于决策树模型的用户购物行为预测分析模型。该模型可以帮助企业预测用户的购物意愿、购物频率及购买金额等重要指标,为企业制定更有针对性的营销策略提供......
  • r语言有限正态混合模型EM算法的分层聚类、分类和密度估计及可视化|附代码数据
    原文链接:http://tecdat.cn/?p=23825最近我们被客户要求撰写关于有限正态混合模型EM算法的研究报告,包括一些图形和统计输出。简介本文介绍了基于有限正态混合模型在r软件中的实现,用于基于模型的聚类、分类和密度估计。提供了通过EM算法对具有各种协方差结构的正态混合模型进行参......
  • 2024牛客寒假算法基础集训营1 J 又鸟之亦心 题解
    Question2024牛客寒假算法基础集训营1J又鸟之亦心Solution挺好的一个题,给了我很多启发显然,先二分最大值\(D\),关键在于\(check\)怎么写考虑到两个人是相对的,第\(i\)次之后肯定有一个人在\(a_i\),具体是谁不重要,也不需要关注是怎么走过来的,我们需要去维护另外一个人可......
  • 莫队算法
    简要介绍:莫队算法是先进行分块,然后按照分块来排序,然后对已知区间进行增减以达到所求区间,记录下答案,最后按照所询问的顺序进行输出答案。如对于已知区间[l,r]要求[l-1,r],[l-2,r],[l-3,r],[l-4,r],则将已知区间向左移,同时进行add添加操作;而对于要求[l,r+1],[l,r+2],[l,r+3],[l,r+......
  • 文心一言 VS 讯飞星火 VS chatgpt (193)-- 算法导论14.3 1题
    一、用go语言,写出作用于区间树的结点且在〇(1)时间内更新max属性的过程LEFT-ROTATE的伪代码。文心一言:以下是一个简单的LEFT-ROTATE的伪代码,它对一个二叉搜索树进行左旋转操作。这个操作的作用是更新节点的max属性,使其在O(1)时间内完成。LEFT-ROTATE(T,x)://T是树,x......
  • 2024牛客寒假算法基础集训营1 K 牛镇公务员考试 题解
    Question2024牛客寒假算法基础集训营1K牛镇公务员考试给出一张试卷有\(n\)道单选题,每道题用一个整数\(a_i\)和一个长度为\(5\)的字符串\(s_i\)表示,其中第\(i\)道题的题面为:第\(a_i\)道题的答案是()A.\(s_1\)B.\(s_2\)C.\(s_3\)D.\(s_4\)E.\(s_5\)问:正......
  • 【算法专题】排序详解
    各种排序快速排序、归并排序、桶排序、堆排序1、快速排序(quick_sort)时间复杂度:\(O(nlogn)\)//快速排序模版voidquick_sort(intq[],intl,intr)//数组,左端点,右端点{if(l>=r)return;//“>>”:右移运算符,相当于除以2intx=q[l+r>>1],......
  • 代码随想录算法训练营第一天 | 27. 移除元素 | 704. 二分查找
     704.二分查找 已解答简单 相关标签相关企业 给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。示例1:输入:numstarget输出:解释:nums......
  • 代码随想录算法训练营第十一天 | 20. 有效的括号 | 1047. 删除字符串中的所有相邻重
     有效的括号 已解答简单 相关标签相关企业 提示 给定一个只包括 '(',')','{','}','[',']' 的字符串 s ,判断字符串是否有效。有效字符串需满足:左括号必须用相同类型的右括号闭合。左括号必须以正确的顺序闭合。每个右括号都有一个对应......