首页 > 其他分享 >浅谈树上问题

浅谈树上问题

时间:2023-07-14 22:58:08浏览次数:35  
标签:浅谈 text Omicron mx 问题 leq LCA 树上 节点

树的直径

定义

规定树上任意两节点之间的最远距离为树的直径

解法

较为主流的解法有两种

  1. 贪心

    以任意节点 \(x\) 为根进行一次 \(\text{DFS}\) ,记录距 \(x\) 最远的节点编号为 \(y\) ,再以 \(y\) 为根进行第二次 \(\text{DFS}\) ,得到距 \(y\) 最远的节点编号 \(z\) ,那么 \(dis(x,y)\) 即为树的直径。

    其中利用了一个定理:在一棵树上,从任意节点 \(x\) 开始进行一次 DFS,到达的距离其最远的节点 \(y\) 必为直径的一端。

    可惜的是该算法只在边权非负的时候成立,关于该做法的正确性可见 OI Wiki ,此处不再赘述。

  2. dp

    该种方法可以解决贪心解法无法处理的负权图。

    首先需要明确一个结论,对于一个有根树,树的直径只有两种情况

    • 直径的两个端点分别在根的两个子树当中

    • 根是直径的一个端点

    明确这件事以后我们就可以利用分治的思想求解了,我们只需要考虑端点不在同一个子树内的情况,在递归中将情况 \(2\) 转化为情况 \(1\) 求解。

    定义 \(f_u\) 为以 \(u\) 为根的子树中的最长链, \(g_u\) 为以 \(u\) 为根的子树中的次长链(与最长链不相交),这样问题就被转化为了上面讨论的情况 \(1\) 了,即 \(\max\limits_{u\in Tree}\{f_u+g_u\}\) 即为树的直径。

动态直径

此处的动态指的是改变树上任意一边的边权(无论操作是否独立),该问题有很多种解法,例如: \(\text{ddp}\) 、\(\text{LCT}\) 、动态点分治等,但此处暂时只介绍线段树维护欧拉序的做法。

  1. 线段树维护欧拉序

    此做法是正确性是基于边权非负的基础上的。

    定义 \(dep_u\) 为点 \(u\) 到树根的距离,首先不难得到树上任意两点之间的距离 \(dis(u,v)\) 满足该式:

    \[dis(u,v) = dep_u + dep_v - 2 \times dep_{LCA(u,v)} \]

    如果熟悉欧拉序,不难知道 \(\text{LCA}\) 可以被规约为 \(\text{RMQ}\) 问题,那么问题就被转化为求这样一个值

    \[\max_\limits{1\leq l \leq r \leq 2\times n - 1}\{A_l + A_r - 2\times \min_\limits{l\leq i \leq r}A_i\} \]

    其中 \(A_i\) 为欧拉序为 \(i\) 的节点的深度

    对于上式,我们可以考虑固定左边界,维护该式:

    \[rmax_{[L,R]} = A_i - 2\times \min_\limits{i\leq j}\{A_j\}\quad(L\leq i \leq j \leq R) \]

    对应的,我们也需要固定右边界,维护这个式子:

    \[lmax_{[L,R]} = A_i - 2 \times \min_\limits{j\leq i}\{A_j\}\quad (L\leq j \leq i\leq R) \]

    因此对于每一个线段树上的节点,我们需要维护如下信息:

    \[\begin{cases} \text{mx} & 表示欧拉序位于该区间中的节点的最大深度 \\ \text{mn} & 表示欧拉序位于该区间中的节点的最小深度 \\ \text{dia} & 表示欧拉序位于该区间中的子树直径 \\ \text{lmx} & 上文所提到的信息 \\ \text{rmx} & 同上 \end{cases} \]

    同时也不难得到如何合并信息

    struct info
    {
        i64 mx, mn, lmx, rmx, dia, tag;
        info() { mx = mn =  lmx = rmx = tag = 0; }
        info operator+(const info& a) const {
            info now;
            now.mx = max(mx, a.mx);
            now.mn = min(mn, a.mn);
            now.lmx = max({lmx, a.lmx, mx - 2 * a.mn});
            now.rmx = max({rmx, a.rmx, a.mx - 2 * mn});
            now.dia = max({dia, a.dia, mx + a.rmx, lmx + a.mx});
            return now;
        }
    };
    
    

    对于线段树来说,我们只需要一个能实现区间加的线段树即可,此处不多赘述。

LCA

倍增

年轻人的第一种求 LCA 的算法!

记 \(fa_{i,x}\) 为 \(i\) 号节点的 \(2^{x}\) 级祖先,这个信息只需要一次 DFS 就可以统计出来。

然后开始倍增,利用 \(fa_{i, x - 1}\) 和 \(fa_{fa_{i, x - 1}, x - 1}\) 得到 \(fa_{i, x}\) (即当前节点 \(x - 1\) 级祖先的 \(x - 1\) 级祖先是当前节点的 \(x\) 级祖先),不难发现预处理所有 \(fa_{i, x}\) 的时间复杂度为 \(\Omicron(n\log n)\)

在求解 \(LCA(u,v)\) 时,我们需要先将深度较深的节点向上跳,使得 \(u\) 和 \(v\) 处在同一深度,若两点重合,那么该点即为二者的 LCA ,否则两节点需同时倍增向上跳直到两节点的父亲节点相同,此时他们的父亲节点就是 \(LCA(u,v)\) ,该部分时间复杂度为 \(\Omicron(\log n)\)

总时间复杂度为 \(\Omicron(n\log n) - \Omicron(\log n)\) ,空间复杂度为 $ \Omicron(n\log n)$

欧拉序

欧拉序从根节点出发到回到根节点为止,按 DFS 的顺序所经过的所有点的顺序,因此有结论,两个点在欧拉序中第一次出现的位置之间一定有它们的 LCA,且它们的 LCA 是这个区间中深度最小的那个点,因此 LCA 问题就可以被转化成为 RMQ 问题,如果用 ST 表维护深度,最终是可以做到时间复杂度 \(\Omicron(n\log n) - \Omicron(1)\) ,空间复杂度 $ \Omicron(n\log n) $ 的。

树链剖分

前置芝士

当 \(top_u \ne top_v\),且 \(dep_{top_u} \ge dep_{top_v}\) 时,使得 \(u\) 变为其所在重链链首的父亲,直到 \(top_u = top_v\) 后,两者深度较小的点即为 \(LCA(u,v)\) ,时间复杂度 \(\Omicron(n) - \Omicron(\log n)\) ,空间复杂度 $ \Omicron(n) $

DSU On Tree

点分治

虚树

笛卡尔树

标签:浅谈,text,Omicron,mx,问题,leq,LCA,树上,节点
From: https://www.cnblogs.com/Jadebo1/p/17555176.html

相关文章

  • 关于线程问题的探讨(售票问题)
    packageSellTickets;publicclassSellTickets01implementsRunnable{privatestaticintticketNum=100;@Overridepublicvoidrun(){while(true){if(ticketNum<=0){System.out.pr......
  • 修复域名访问问题
    研究了一下午,一开始思考为什么不能一直用域名访问,在主页面点进新页面后就不能继续使用域名访问了,所以就开始修复这个问题,问了问AI是反向代理服务器的问题,结果给我网站搞崩了,查了一堆资料还是没解决,结果自己随便逛了逛宝塔面板,看到PHP是静态的,我就知道问题了,妈的,还是自己的脑袋聪......
  • 配置问题-Error creating bean with name 'user' defined in class path resource [be
    正在学习IoC使用的jdk版本为jdk17依赖为:<dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-core</artifactId><version>6.0.6</version></dependen......
  • BZOJ #3784. 树上的路径
    BZOJ#3784.树上的路径题意给一颗树,求所有路径长度中前\(k\)大。题解首先对于前\(k\)大,我们有一个常见的方法,二分。二分第\(k\)大的路径长度,然后使用点分治统计,点分治内部还要二分,所以时间复杂度\(O(nolg^3n)\)。二分显然是行不通了,想一下就会发现外层和内层的二分......
  • SQL注入问题、视图、触发器、事务、存储过程、函数、流程控制、索引、测试索引
    SQL注入问题连接MySQL服务器conn=pymysql.connect(host=‘127.0.0.1’port=3306user=‘root’password='1234'......
  • 浅谈生成式人工智能
    本文分享自天翼云开发者社区《浅谈生成式人工智能》,作者:赖****生一、什么是生成式人工智能?生成式人工智能是指:利用机器学习技术让计算机自动生成不同模态(比如文本,图片,语音等)高质量数据的方法。尽管过去几十年的人工智能研究迭代出了无数的生成模型,但生成式人工智能被当成一种......
  • 了不起的魔术师问题
    目录了不起的魔术师问题前言问题描述解决方案参考了不起的魔术师问题前言此问题来自于<<Python编程:从入门到实践>>第一版中习题8-10.问题描述了不起的魔术师:创建一个包含魔术师名字的列表,并将其传递给一个名为show_magicians()的函数,这个函数打印列表中每个魔术......
  • Qt信号槽信号函数重载问题 error: C2664: “QMetaObject::Connection const”
    //connect(spinFontSize,&QSpinBox::valueChanged,this,&MainWindow::spinFontSize_valueChanged);//由于信号函数存在重载,发送者找不到正确信号函数。//改用A.Qt4带形参方式//connect(spinFontSize,SIGNAL(valueChanged(int)),this,SLOT(spinFontSize_valueChang......
  • vue进行页面跳转样式丢失问题
    问题:vue使用 this.$router.push方法进行页面跳转时样式丢失,如下图,图一为正常页面,图二为跳转后的界面  解决方法:并非样式丢失,而是样式背覆盖了,去跳转的原界面样式中加入scope,跳转之后问题解决 ......
  • 自定义图标偏移问题
    在地图开发中使用自定义图标(icon)在地图上表达专题信息十分常见leaflet中常使用L.marker添加图标L.icon,非常方便给定坐标将图标固定在地图中的某个位置,由于图标是有具体大小,并且大小固定不变,在缩放过程中有明显感觉随着地图比例尺缩小,图标会有一定的偏移这篇文章主要介绍使用L......