DFS序求LCA
DFS序求LCA
介绍
欧拉序求LCA 的数组总是会忘记开两倍,并且预处理的常数较大。用 DFS序求LCA 可以解决这些问题。
欧拉序:进节点和出节点会重复记录节点。
DFS序:深度优先搜索的顺序,不会重新记录。
假设要求 \(lca(u,v)\), 且 \(dfn[u] < dfn[v]\)。
那么 \(dfn[u] \sim dfn[v]\) 的所有点都在 \(lca(u,v)\) 子树中。
其中包括 \(lca\) 在 \(v\) 方向上的第一个点 \(x\), 显然这个点是 \(dfn[u] \sim dfn[v]\) 中 \(dep\) 最小的,和 欧拉序求LCA 一样, 我们用 st表 找到这个位置就可以,min函数改为 比较dep。
这样就找到了 \(x\), 那么 \(lca(u,v) = fa[x]\)。
说明: 找 \(x\) 的原因是因为 \(lca\) 的 \(dfn\) 不一定在这个范围内。
还有一种不用记录 \(dep\) 仅依靠 \(dfn\) 求解 lca 的小技巧:\(dfn\) 改为记录每个点的父节点, 最终 st表求出的值就是 lca。(详情见参考博客)
\(dfn[u] + 1\) 的原因是考虑到了 \(u, v\) 在同一条链上的情况。
struct LCA{
struct node{
int v, ne;
}e[N << 1];
int first[N], idx = 0;
int dep[N], fa[N], dfn[N], rev[22][N], cnt = 0;
void add(int x, int y){
e[++ idx] = (node){y, first[x]};
first[x] = idx;
}
void dfs(int u, int f){
fa[u] = f;
dep[u] = dep[f] + 1;
dfn[u] = ++ cnt;
rev[0][cnt] = u;
for(int i = first[u]; i; i = e[i].ne){
int v = e[i].v;
if(v == f) continue;
dfs(v, u);
}
}
int cmin(int x, int y){
if(dep[x] < dep[y]) return x;
return y;
}
int getlca(int x, int y){
if(x == y) return x;
if((x = dfn[x]) > (y = dfn[y])) swap(x, y);
int t = __lg(y - x++);
return fa[cmin(rev[t][x], rev[t][y - (1 << t) + 1])];
}
void init(){
dfs(root, 0);
F(j, 1, 20) F(i, 1 , n - (1 << j) + 1) rev[j][i] = cmin(rev[j - 1][i], rev[j - 1][i + (1 << (j - 1))]);
}
}lca;
参考博客
冷门科技 —— DFS 序求 LCA - By Alex_Wei
DFS序求LCA的更多相关文章
- P3703 [SDOI2017]树点涂色 LCT维护颜色+线段树维护dfs序+倍增LCA
\(\color{#0066ff}{ 题目描述 }\) Bob有一棵\(n\)个点的有根树,其中1号点是根节点.Bob在每个点上涂了颜色,并且每个点上的颜色不同. 定义一条路径的权值是:这条路径上的点 ...
- D - Project Presentation(DFS序+倍增LCA)
You are given a tree that represents a hierarchy in a company, where the parent of node u is their d ...
- dfs序 + RMQ = LCA
dfs序是指你用dfs遍历一棵树时,每个节点会按照遍历到的先后顺序得到一个序号.然后你用这些序号,可以把整个遍历过程表示出来. 如上图所示,则整个遍历过程为1 2 3 2 4 5 4 6 4 2 1 ...
- bzoj 2819 Nim(BIT,dfs序,LCA)
2819: Nim Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 1596 Solved: 597[Submit][Status][Discuss] ...
- luogu3320 寻宝游戏 (dfs序+倍增lca+set)
一定是从随便某个点开始,然后按着dfs序的顺序跑一圈是最好的 所以说,新加一个点x,就减少了dis(pre,next),增加了dis(pre,x),dis(x,nxt) 删掉一个点同理 这个可以用se ...
- Codeforces Round #384 (Div. 2) A B C D dfs序+求两个不相交区间 最大权值和
A. Vladik and flights time limit per test 2 seconds memory limit per test 256 megabytes input standa ...
- 蓝皮书:异象石 【dfs序+lca】
题目详见蓝皮书[算法竞赛:进阶指南]. 题目大意: 就是给你一颗树,然后我们要在上面进行三种操作: 1.标记某个点 或者 2.撤销某个点的标记 以及 3.询问标记点在树上连通所需的最短总边 ...
- BZOJ 2819: Nim( nim + DFS序 + 树状数组 + LCA )
虽然vfleaking好像想卡DFS...但我还是用DFS过了... 路径上的石堆异或和=0就是必败, 否则就是必胜(nim游戏). 这样就变成一个经典问题了, 用DFS序+BIT+LCA就可以在O( ...
- 【BZOJ】1146: [CTSC2008]网络管理Network(树链剖分+线段树套平衡树+二分 / dfs序+树状数组+主席树)
http://www.lydsy.com/JudgeOnline/problem.php?id=1146 第一种做法(时间太感人): 第二种做法(rank5,好开心) ================ ...
- 【BZOJ3772】精神污染 DFS序+主席树
[BZOJ3772]精神污染 Description 兵库县位于日本列岛的中央位置,北临日本海,南面濑户内海直通太平洋,中央部位是森林和山地,与拥有关西机场的大阪府比邻而居,是关西地区面积最大的县,是 ...
随机推荐
- Codeforces Round 911 (Div. 2) D
Codeforces Round 911 (Div. 2) D D. Small GCD 题意 定义\(f(a,b,c)\)为\(a,b,c\)中较小两个数的\(gcd\),给定数组\(a_{1... ...
- 一文搞懂Cortex-A9 ADC裸机和基于Linux驱动编写方法
前言 在嵌入式开发中,ADC应用比较频繁,本文主要讲解ADC的基本原理以及如何编写基于ARM的裸机程序和基于Linux的驱动程序. ARM架构:Cortex-A9 Linux内核:3.14 在讲述AD ...
- 如何将一个模块文件编译到Linux内核中?
很多粉丝在群里提问,如何把一个模块文件编译到内核中或者独立变异成ko文件.本文给大家详解讲解. 1. 内核目录 Linux内核源代码非常庞大,随着版本的发展不断增加.它使用目录树结构,并且使用Make ...
- kubernetes批量删除evicted状态pod
#!/bin/bash # get namespace namespaces=`kubectl get pod -A | grep -i "evicted" | awk '{pri ...
- JavaScript设计模式样例九 —— 桥接模式
桥接模式(Bridge Pattern) 定义:是用于把抽象化与实现化解耦,使得二者可以独立变化. 目的:将抽象部分与实现部分分离,使它们都可以独立的变化. 场景:实现系统可能有多个角度分类,每一种角 ...
- OBS直播抠绿插件(Matting123)
一.产品概述 OBS直播抠绿插件(Matting123)是使用绿幕.蓝幕进行抠像的虚拟直播软件,本软件需要配合OBS30.0.0或以上版本进行使用.Matting123采用自研抠图算法,该算法已达到影 ...
- Vue状态管理库Pinia详解
Pinia 是 Vue 的状态管理库,它提供了一种更简单.更不规范的 API 来管理应用的状态.Pinia 的设计哲学是简单性和易用性,它避免了 Vuex 中的许多复杂概念,如 mutations 和 ...
- 搭建QT开发环境
下载 Qt官网,Qt下载网址 安装前要登录账号,其他的该咋就咋样,路径不能有中文. 组件自己选 我的是MinGW.Android.虚拟键盘.Qt脚本.Qt Creator 然后创个项目,能跑起来就是安 ...
- .NET 开源实时监控系统 - WatchDog
前言 在平时的开发中随着我们系统应用不断地迭代变的复杂,对应用的实时监控变得越来越重要.实时监控不仅可以帮助我们快速定位问题,还能在出现问题时及时采取措施,减少业务中断的时间. 本文将介绍一个名为Wa ...
- C# 导出datatable数据到excel
第一步:下载两个需要的NUGET包 1.org.in2bits.MyXls:2.NPOI 第二步:关键类OutExcel. using System; using System.Linq; using ...