LCA问题的ST,tarjan离线算法解法

本文介绍了ST算法解决RMQ问题的方法及应用到LCA问题的解决方案,包括使用DP思想预处理数组,以及如何利用这些预处理结果进行快速查询。此外还介绍了tarjan离线算法解决LCA问题的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一  ST算法与LCA

  • 介绍

第一次算法笔记这样的东西,以前学算法只是笔上画画写写,理解了下,刷几道题,其实都没深入理解,以后遇到新的算法要把自己的理解想法写下来,方便日后回顾嘛>=<

RMQ问题就是询问一个给定数组相应区间i…j的最大值。

ST算法的思路是:f(i,j)表示i开始的2^j个数中最大值/最小值,通过运用dp的思想初始化f(i,j)求出每个i(1….n)出发长度为2^j(0<=j<=log(n)/log(2))最大值。

由于初始化过程复杂度只有O(nlog(n)),查询过程O(1),所以会比线段树快很多,而且更不容易出错。

以下为初始化代码:

Init:

for(int i = 1; i <= n; i++)

   f(i, 0) = a[i];

for(int i = 1; i <= (int)log(n)/log(2); i++)

    for(int j = 1; j + (1<<i) – 1 <= n; j++)

        f(i, j) = max(f (i , j-1), f(i+(1<<(j-1) ), j - 1);

查询区间[a, b],先找到一个最大的值k = (int)log(b-a+1)/log(2);

然后分别查询左右两个端点出发的长度为2^k的区间最大值。

RMQ(a, b)

   int k = (int)log(b-a+1)/log(2.0);

return max(f(a, k), f(b – (1<<k) + 1, k));

  • 解决LCA问题

在dfs遍历过程中,每次进入或回溯到结点u时,将深度存入熟读dep[cnt],cnt表示在数组中的编号,同时用E[cnt]记录相应的结点即:E[cnt] = u, 并且用R数组记录初次访问u的时候,存进D数组的位置,即R[u] = cnt.

这样每次查询LCA(u,v) = E[RMQ(dep, R[u], R[v])], (R[u] < R[v]),RMQ返回到的是下标R[u]~R[v]的区间中深度最小的点在数组中的位置,也就是下标,这样通过E数组可获得该结点编号。

dfs(u, d)
     R[u] = ++cnt
     dep[cnt] = d
     E[cnt] = u
     vis[u] = true
     for each (u, v) in TREE
           if  !vis[v]
              dfs(v, d+1)
              dep[++cnt] = d
              E[cnt] = u

最后cnt 的大小为2*n-1,也就是每条边访问了2次。

 

最近遇到的一个问题是,HDU – 3686  Traffic Real Time Query System 对双连通分量缩点,使得割点和各个连通分量构成一个树形图,求这个树形图中任意两点之间路径最少需要经过多少个割点,稍有变化

只是在遇到割点时距离才增加,而且当LCA(u, v)是割点的时候需要把结果ans++。

题解: HDU Traffic Real Time Query System

二 tarjan离线算法解决LCA

主要是事先读入所有的查询,然后在dfs到u的过程中,看所有需要查询的(u,v)中另一点v是否已经访问过,如果是的话此时findset(v)便是u,v的LCA。

通过ans = dis[u] + dis[v] – 2 * dis[findset(v)]便可知道u,v间的最短距离。

 

常见的LCA问题就是求树形图中2个点的最短距离,3个点连接起来的最短距离,都是通过两两求出最短距离然后除以2(对于3个点的情况),是不是n个点的时候除以(n-1)?猜了一下,求高手证实、==

3个点:题解 ZOJ - 3195 Design the city。2个点的类似: HDU – 2586  How far away ?

 

tarjan离线解决HDU Traffic Real Time Query System 题解.

更详细的解释 博客 在这里了,遇到一个LCA的题目,就学习了一下,我只是做了一个新手搬运工hahaha~

 

 

资源下载链接为: https://pan.quark.cn/s/d9ef5828b597 在本文中,我们将探讨如何通过 Vue.js 实现一个带有动画效果的“回到顶部”功能。Vue.js 是一款用于构建用户界面的流行 JavaScript 框架,其组件化和响应式设计让实现这种交互功能变得十分便捷。 首先,我们来分析 HTML 代码。在这个示例中,存在一个 ID 为 back-to-top 的 div 元素,其中包含两个 span 标签,分别显示“回到”和“顶部”文字。该 div 元素绑定了 Vue.js 的 @click 事件处理器 backToTop,用于处理点击事件,同时还绑定了 v-show 指令来控制按钮的显示与隐藏。v-cloak 指令的作用是在 Vue 实例渲染完成之前隐藏该元素,避免出现闪烁现象。 CSS 部分(backTop.css)主要负责样式设计。它首先清除了一些默认的边距和填充,对 html 和 body 进行了全屏布局,并设置了相对定位。.back-to-top 类则定义了“回到顶部”按钮的样式,包括其位置、圆角、阴影、填充以及悬停时背景颜色的变化。此外,与 v-cloak 相关的 CSS 确保在 Vue 实例加载过程中隐藏该元素。每个 .page 类代表一个页面,每个页面的高度设置为 400px,用于模拟多页面的滚动效果。 接下来是 JavaScript 部分(backTop.js)。在这里,我们创建了一个 Vue 实例。实例的 el 属性指定 Vue 将挂载到的 DOM 元素(#back-to-top)。data 对象中包含三个属性:backTopShow 用于控制按钮的显示状态;backTopAllow 用于防止用户快速连续点击;backSeconds 定义了回到顶部所需的时间;showPx 则规定了滚动多少像素后显示“回到顶部”按钮。 在 V
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值