倍增(ST表与LCA)

article/2025/9/29 16:10:13

倍增(ST表与LCA)

什么是倍增?

倍增,就是成倍增长。指我们进行递推时,如果状态空间很大,通常线性递推无法满足时空复杂度要求,那么可以通过成倍增长的方式,只递推状态空间中 2 的整数次幂位置的值为代表将复杂度优化成log级别。

为什么倍增是正确的?

我们通过任意整数可以表示成若干个 2 的整数次幂的和这一性质来表示任意一个区间长度。例如:5 = 101 = 2 ^ 2 + 2 ^ 0;

倍增思想应用于哪些问题?

倍增最常见应用就是求解 RMQ问题和LCA问题

ST表

什么是ST表?

ST表是基于倍增思想解决可重复贡献问题的数据结构。

其中ST表最广泛的应用就是解决RMQ(区间最值问题): 给定一个包含n个数的数组,以及m次询问,每次询问给出一个区间**[l, r]**,需要我门输出区间中的最小/大值。

基于倍增的思想,ST表可以实现 O(NlogN) 下进行预处理,并在O(1) 时间内回答每个询问。但是,ST表并不支持修改操作。

如何维护ST表?

我们定义数组**f[i][j]**表示下标从 i 开始长度为 2 ^ j 的区间中最小/大值。根据倍增的思想不难想出:

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

并且可以通过O(NlogN)的时间来预处理出所有f[i][j]的值。

在这里插入图片描述

对于每次询问[l, r],我们先计算出区间长度 len = r - l + 1。再对区间长度len取对数:
K = log ⁡ 2 l e n K = \log_2 len K=log2len
对于log函数的值我们可以通过**O(N)**的时间预处理出来。

再将区间分成 [l , l + 2 ^ k - 1][r - 2 ^ k + 1, r], 由于k 是整数可能存在精度误差,但是 2 ^ k + 1 > len ,这样就可以避免整数类型带来的误差。

在这里插入图片描述

练习:

ST表模板题:

#include <iostream>
#include <algorithm>
using namespace std;
const int N = 1e5 + 10;
int a[N], stmax[N][20], mn[N];
int n, q;
void init()
{mn[0] = -1;for (int i = 1; i <= n; i++){mn[i] = ((i & (i - 1))== 0) ? mn[i - 1] + 1 : mn[i - 1];stmax[i][0] = a[i];}for (int j = 1; j <= mn[n]; j++){for (int i = 1; i + (1 << j) - 1 <= n; i++){stmax[i][j] = max(stmax[i][j - 1], stmax[i + (1 << (j - 1))][j - 1]);}}
}
int query(int l, int r)
{int k = mn[r - l + 1];return max(stmax[l][k], stmax[r - (1 << k) + 1][k]);
}
int main()
{scanf("%d%d", &n, &q);for (int i = 1; i <= n; i++){scanf("%d", &a[i]);}init();for (int i = 0; i < q; i++){int l, r;scanf("%d%d", &l, &r);printf("%d\n", query(l, r));}return 0;
}

LCA(最近公共祖先)

什么是LCA(最近公共祖先)?

祖先:指的是一个结点向根节点遍历的路径上经过的所有结点(包括该节点本省身)。

LCA指的是在一个有N个点的有根树中,给出m个询问,每个询问包含两个树上结点,需回答距离这两个结点最近的(深度最深的结点)。

在这里插入图片描述

如何解决LCA问题?

LCA问题的解法有很多:向上标记法,倍增法, tarjan等等,今天要介绍的是最简单且最常用的倍增法。

倍增法LCA基于倍增思想,可以通过O(NlogN)预处理,每次查询的时间复杂度为O(logN)

倍增法求解LCA问题具体如何实现?

我们定义fa[i][j],表示从i号结点开始向上走2 ^ j (0 <= j <= logN)步能够走到的结点, depth[i] 表示i号点的深度。

同样是倍增的思想,我们不难推出:

当 j == 0 时fa[i][j]表示的是i结点的父亲结点

当 j > 0 时 fa[i][j] = fa[ fa[i][j - 1] ][j - 1];

在这里插入图片描述

对于每次询问求解两个点的LCA可以分为一下步骤:

(1)、先将两个点向上跳到同一层(深度相同): 例如 depth[A] = 7, depth[B] = 4, 则应该先将A点向上跳

​ t = 7 - 4 = 3 = 011(B) 步[采用二进制并凑法] 跳到与B同一层;

(2)、再将这两个点同时向上跳直到跳到A, B两点的LCA的下一层为止。(为什么不直接跳到LCA?,因为j >= 0 时 2的整数次幂最小值为1);

(3)、此时的fa[A][0]即是A,B两点的LCA;

练习

LCA模板题

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#define int long long
using namespace std;
const int N = 1e6 + 10;
int n, root, m;
int h[N], e[N], ne[N], idx;
int f[N][40], depth[N], q[N];
void add(int a,int b){e[idx] = b;ne[idx] = h[a];h[a] = idx ++;return ;
}
void dfs(){memset(depth, 0x7f, sizeof(depth));depth[0] = 0;depth[root] = 1;int hh = 0, tt = 0;q[0] = root;while(hh <= tt){int t = q[hh ++];for(int i = h[t]; i != -1; i = ne[i]){int j = e[i];if(depth[j] > (depth[t] + 1)){depth[j] = depth[t] + 1;q[++ tt] = j;f[j][0] = t;for(int k = 1; k <= 19; k ++){f[j][k] = f[f[j][k - 1]][k - 1];}}}}
}
int lca(int a, int b){if(depth[a] < depth[b]){swap(a, b);}for(int k = 19; k >= 0; k --){if(depth[f[a][k]] >= depth[b]){a = f[a][k];}}if(a == b){return a;}for(int k = 19; k >= 0; k --){if(f[a][k] != f[b][k]){a = f[a][k];b = f[b][k];}}return f[a][0];
}
signed main(){memset(h, -1, sizeof(h));scanf("%lld%lld%lld",&n, &m, &root);for(int i = 0; i < n - 1; i ++){int a, b;scanf("%lld%lld",&a, &b);add(a, b);add(b, a);}dfs();for(int i = 0; i < m ; i ++){int a, b;scanf("%lld%lld",&a, &b);printf("%lld\n",lca(a, b));}}

http://chatgpt.dhexx.cn/article/0er0yofk.shtml

相关文章

V4L2-框架

1.概述 V4L2 是专门为linux 设备设计的一套视频框架&#xff0c;其主体框架在linux内核&#xff0c;可以理解为是整个linux系统上面的视频源捕获驱动框架。 相机驱动层位于HAL Moudle 与硬件层之间&#xff0c;借助linux 内核驱动框架&#xff0c;以文件节点的方式暴露接口给用…

V4L2学习笔记

首先附上&#xff0c;Linux内核网站&#xff1a; 入口 v4l2非常棒的一篇文章 入口 内核代码查看&#xff1a; 入口 一个博客文档&#xff1a; 入口 https://lwn.net/Articles/204545/ 别人整理 关于linux内核头函数&#xff1a; /usr/src/xxx 系列文 在其内部有media文件…

V4L2框架学习

V4L2框架 0 查看videodev2 0.1 头文件/usr/include/linux/videodev2.h 0.2 使用ioctl函数 使用ioctl函数 // 添加头文件 #include <unistd.h> #include <sys/ioctl.h> #include <linux/videodev2.h>int ioctl (int __fd, unsigned long int __request, ...…

V4L2介绍

V4L2介绍 V4L2介绍主要功能框架v4L2编程 V4L2介绍 V4L2是Video for linux2的简称,为linux中关于视频设备的内核驱动。在Linux中&#xff0c;视频设备是设备文件&#xff0c;可以像访问普通文件一样对其进行读写&#xff0c;摄像头在/dev/video*下&#xff0c;如果只有一个视频…

linux V4L2子系统——v4l2架构(7)之V4L2应用编程

linux V4L2子系统——v4l2架构&#xff08;7&#xff09;之V4L2应用编程 备注&#xff1a;   1. Kernel版本&#xff1a;5.4   2. 使用工具&#xff1a;Source Insight 4.0   3. 参考博客&#xff1a; &#xff08;1&#xff09;Linux V4L2子系统-应用层访问video设备&a…

[2022.8.15]v4l2-ctl基本使用方法

v4l2-ctl使用帮助可以参考&#xff1a;https://www.mankier.com/1/v4l2-ctl 1 v4l2-ctl --list-devices 列出所有设备 USB 2.0 Camera: USB Camera (usb-0000:00:14.0-9):/dev/video0/dev/video1 一个USB camera对应两个设备&#xff1a;一个是图像/视频采集&#xff0c;一…

V4L2应用层分析

V4L2应用层分析 一、总述二、例子 一、总述 V4L2&#xff0c;即Video for Linux 2&#xff0c;是第二代为Linux打造的音频、视频驱动。相比第一代V4L&#xff0c;V4L2支持更多的设备&#xff0c;同时更加稳定。现今的视频设备&#xff0c;如USB摄像头&#xff0c;基本都支持V4…

v4l2数据结构分析

v4l2数据结构分析 文章目录 v4l2数据结构分析Video4Linux2设备v4l2_device媒体设备media_deviceVideo4Linux2子设备v4l2_subdevVideo4Linux2子设备的操作集v4l2_subdev_opsVideo4Linux2子设备的内部操作集v4l2_subdev_internal_opsVideo4Linux2控制处理器v4l2_ctrl_handlerVide…

摄像头V4L2编程应用开发

1.V4L2简介 Video for Linux two(Video4Linux2)简称V4L2&#xff0c;是V4L的改进版。V4L2是linux系统操作系统下一套用于采集图片、视频、和音视频数据的通用API接口&#xff0c;配合适当的视频采集设备和相应的驱动程序&#xff0c;可以实现图片、视频、音频等的采集。 在linu…

V4L2框架

前言 在分析v4l2之前最好具有的知识&#xff1a; 1.字符设备,因为v4l2是被枚举为字符设备。 2.内存分配和映射,比如相关数据结构的分配和buffer。 3.DMA&#xff0c;因为v4l2的数据传输用到了DMA。 4.I2C&#xff0c;因为很多传感器都是用的i2c接口。 5.文件系统的基本操作&am…

V4L2系列 之 V4L2驱动框架

目录 前言一、V4L2驱动框架概览1、应用层 -》中间层-》驱动层2、主要代码文件(Linux 4.19版本内核) 二、怎么写V4L2驱动1、如何写一个设备的驱动&#xff1f;2、Video设备主要结构体3、怎么写V4L2驱动 三、V4L2的调试工具1、v4l2-ctl2、dev_debug3、v4l2-compliance 前言 本篇文…

V4L2框架概述

原文链接 本文开启 linux 内核 V4L2 框架部分的学习之旅&#xff0c;本文仅先对 V4L2 的框架做一个综述性的概括介绍&#xff0c;然后接下来的文章中会对 V4L2 框架的各个子模块进行一个全面的介绍&#xff0c;包括每一部分的实现原理&#xff0c;如何使用&#xff0c;用在什么…

V4l2框架分析

Table of Contents 1.V4L2框架概述 1.1 v4l2设备应用层流程 1.2 内核V4L2模块 1.2.1 video_device 1.2.2 v4l2_subdev 1.2.3 videobuf2 2. video_device结构体 2.1 图像处理模块 2.2 video_device处理流程 2.2.1 video_device 结构体成员介绍: 3. video_buf2 3.1 …

V4L2

V4L2(video 4 linux 2) V4L2有一段历史了。大约在1998的秋天&#xff0c;它的光芒第一次出现在Bill Dirks 的眼中。经过长足的发展&#xff0c;它于2002年11 月&#xff0c;发布2.5.46 时&#xff0c;融入了内核主干之中。然而直到今天&#xff0c;仍有一部分内核驱不支持新的A…

V4L2简介

http://work-blog.readthedocs.org/en/latest/v4l2%20intro.html 第一章 V4L2简介 1.1、什么是v4l2 V4L2&#xff08;Video4Linux的缩写&#xff09;是Linux下关于视频采集相关设备的驱动框架&#xff0c;为驱动和应用程序提供了一套统一的接口规范。 V4L2支持的设备十分广泛&…

我们一起学linux之V4L2摄像头应用流程

一、概述 Video for Linuxtwo(Video4Linux2)简称V4L2&#xff0c;是V4L的改进版。V4L2是linux操作系统下用于采集图片、视频和音频数据的API接口&#xff0c;配合适当的视频采集设备和相应的驱动程序&#xff0c;可以实现图片、视频、音频等的采集。在远程会议、可视电话、视频…

深入学习Linux摄像头(一)v4l2应用编程

深入学习Linux摄像头&#xff08;一&#xff09;v4l2应用编程 一、什么是v4l2 二、v4l2 API介绍 2.1 Querying Capabilities 2.2 Application Priority 2.3 Device Inputs and Outputs 2.4 Video Standards 2.5 Camera Control Reference 2.6 Image Format 2.7 Cropping, compo…

V4L2驱动框架详解

1. V4L2框架概述 1.1 v4l2设备应用层流程 1.2 内核V4L2模块 2 2. video_device 2.1图像处理模块 2.2 video注册流程 3. videobuf2 3.1 与video device的关系: 3.2 buffer类型 3.3 vb2_ops回调函数 3.4 mmap 流程 4. Subdev 4.1 概念 4.2 subdev注册流程 5. media fra…

html背景自动适应,css背景图片如何自适应?

css可以使用background-size属性设置背景图片自适应&#xff0c;为背景图片设置background-size:cover;样式即可使背景图片自适应。 css可以使用background-size属性设置背景图片自适应。background-size属性规定背景图像的尺寸。 background-size属性&#xff1a; 语法&#x…