倍增算法笔记

news2025/1/11 2:29:50

主要应用场景

RMQ:区间最值问题
LCA:最近公共祖先问题

RMQ问题——区间最值

如果用数组f[N]存储,用数组a[i][j]表示从第i个数起连续 2^j 个数中的最大值,[i,i + 2^j - 1],显然a[i][0] = f[i],则很容易得到状态转移方程:

a[i][j] = max(a[i][j - 1], a[i + 2^(j - 1)][j - 1])

图解

那么我们只需要对开始时,对于数组a进行预处理。我们先更新所有长度为0的情况a[i][0] = f[i]。然后,通过2个1元素的最值a[i][0]获得1个2元素的最值a[i][1],依次类推。
由于这里第二维j表示的是从i起,长度为2^j个数,所以j最大为logn,这里的复杂度应该是O(nlogn)。
此时,对于每一次询问的复杂度为O(1)
如果我们查询区间为[l,r],那么此时区间长度为 (r - l + 1),所以取 k = log(r - l + 1),可以将询问转换成 max(l,r) = max(a[l][k], a[r - (1 << k) + 1][k])。
其中,a[l][k]表示的是区间[l, l + 2^k - 1], a[r - 2^k + 1][k]表示的区间是[r - 2^k + 1, r]。

参考代码

参考例题:洛谷 P3865 【模板】ST 表

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e6 + 3;
int n, t, arr[N][32];

int query(int l, int r)
{
    int k = (int)(log((r - l + 1) * 1.0) / log(2.0));
    return max(arr[l][k], arr[r - (1 << k) + 1][k]);
}

int main()
{
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    cin >> n >> t;
    for (int i = 1; i <= n; ++i)
        cin >> arr[i][0];
    for (int j = 1; j <= (int)(log(n * 1.0) / log(2.0)); ++j)
    {
        for (int i = 1; i + (1 << j) - 1 <= n; ++i)
        {
            arr[i][j] = max(arr[i][j - 1], arr[i + (1 << (j - 1))][j - 1]);
        }
    }
    while (t--)
    {
    	int l, r;
        cin >> l >> r;
        cout << query(l, r) << '\n';
    }
}

LCA问题——最近公共祖先

参考例题:

  1. 洛谷 P3379 【模板】最近公共祖先(LCA)
  2. 蓝桥OJ 最近公共祖先LCA查询

要求两个点的LCA,先将这两个点调整到同一高度(结点高度大的向上跳),之后两个结点同时往上跳,当他们到达同一高度时,该结点即为他们的LCA。
这里关键的是预处理,将每个结点的向上的父节点全部记录下来,方便结点向上跳时候使用。

例1参考代码(C++)

#include <bits/stdc++.h>
using namespace std;
// 2^logn 需要大于 N
const int N = 500003, logn = 22;
struct zzz {
    int t, nex;
}e[N << 1]; 
int head[N], tot;
void add(int x, int y) {
	e[++tot].t = y;
	e[tot].nex = head[x];
	head[x] = tot;
}
int depth[N], fa[N][logn], lg[N];
void dfs(int now, int fath) {
	fa[now][0] = fath; depth[now] = depth[fath] + 1;
	for(int i = 1; i <= lg[depth[now]]; ++i)
		fa[now][i] = fa[fa[now][i-1]][i-1];
	for(int i = head[now]; i; i = e[i].nex)
		if(e[i].t != fath) dfs(e[i].t, now);
}
int LCA(int x, int y) {
	if(depth[x] < depth[y]) swap(x, y);
	while(depth[x] > depth[y])
		x = fa[x][lg[depth[x]-depth[y]] - 1];
	if(x == y) return x;
	for(int k = lg[depth[x]] - 1; k >= 0; --k)
		if(fa[x][k] != fa[y][k])
			x = fa[x][k], y = fa[y][k];
	return fa[x][0];
}
int main() {
	int n, m, s; scanf("%d%d%d", &n, &m, &s);
	// 建树
	for(int i = 1; i <= n-1; ++i) {
		int x, y; scanf("%d%d", &x, &y);
		add(x, y); add(y, x);
	}
	// 预处理
	for(int i = 1; i <= n; ++i)
		lg[i] = lg[i-1] + (1 << lg[i-1] == i);
	dfs(s, 0);
	for(int i = 1; i <= m; ++i) {
		int x, y; scanf("%d%d",&x, &y);
		printf("%d\n", LCA(x, y));
	}
	return 0;
}

例2参考代码

#include <bits/stdc++.h>
using namespace std;
// 2^logn 需要大于 N
const int N = 1e5 + 3, logn = 20;
class TreeEdge
{
public:
    int to, nex;
} edge[N << 1];
// head
int head[N], tot;
void add(int x, int y)
{
    edge[++tot].to = y;
    edge[tot].nex = head[x];
    head[x] = tot;
}
int n, q, depth[N], f[N][logn], lg[N];

void dfs(int now, int fath)
{
    f[now][0] = fath, depth[now] = depth[fath] + 1;
    for (int i = 1; i <= lg[depth[now]]; ++i)
        f[now][i] = f[f[now][i - 1]][i - 1]; // 2^(i - 1) * 2^(i - 1) = 2^i
    for (int i = head[now]; i; i = edge[i].nex)
        if (edge[i].to != fath)
            dfs(edge[i].to, now);
}

int lca(int a, int b)
{
    if (depth[a] < depth[b])
        swap(a, b);
    while (depth[a] > depth[b])
        a = f[a][lg[depth[a] - depth[b]] - 1];
    if (a == b)
        return a;
    for (int k = lg[depth[a]] - 1; k >= 0; --k)
        if (f[a][k] != f[b][k])
            a = f[a][k], b = f[b][k];
    return f[a][0];
}

int main()
{
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    cin >> n;
    for (int i = 1; i < n; ++i)
    {
        int u, v;
        cin >> u >> v;
        add(u, v), add(v, u);
    }
    for (int i = 1; i <= n; ++i)
        lg[i] = lg[i / 2] + 1;
    dfs(1, 0);
    cin >> q;
    while (q--)
    {
        int a, b;
        cin >> a >> b;
        cout << lca(a, b) << '\n';
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1412093.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

免 费 小程序商城搭建之鸿鹄云商 SAAS云产品概述

【SAAS云平台】打造全行业全渠道全场景的SaaS产品&#xff0c;为店铺经营场景提供一体化解决方案&#xff1b;门店经营区域化、网店经营一体化&#xff0c;本地化、全方位、一站式服务&#xff0c;为多门店提供统一运营解决方案&#xff1b;提供丰富多样的营销玩法覆盖所有经营…

Java Web(五)--DOM

介绍 DOM 全称是 Document Object Model 文档对象模型&#xff1b; DOM 是 W3C&#xff08;万维网联盟&#xff09;的标准。 DOM 定义了访问 HTML 和 XML 文档的标准&#xff1a; "W3C 文档对象模型 &#xff08;DOM&#xff09; 是中立于平台和语言的接口&#xff0…

伊恩·斯图尔特《改变世界的17个方程》薛定谔方程笔记

想法是等这学期学到薛定谔方程后再把整份完善下。 它告诉我们什么&#xff1f; 这个方程不是把物质作为粒子&#xff0c;而是作为波&#xff0c;并描述这样的波如何传播。 为什么重要&#xff1f; 薛定谔方程是量子力学的基础&#xff0c;它与广义相对论一起构成了当今最有效的…

JAVA_EE_api_中英文对照版

点击即可下载&#xff1a; JAVA_EE_api_中英文对照版

外包干了4个月,技术退步太明显了。。。。。

先说一下自己的情况&#xff0c;本科生生&#xff0c;18年通过校招进入武汉某软件公司&#xff0c;干了差不多4年的功能测试&#xff0c;今年国庆&#xff0c;感觉自己不能够在这样下去了&#xff0c;长时间呆在一个舒适的环境会让一个人堕落!而我已经在一个企业干了四年的功能…

K/HW/E03-SY850/150型测宽测厚组合测量仪

关键字:测宽测厚组合测量仪,扁钢测宽仪器,板材测厚仪器,冷轧测宽测厚设备,组合测量仪, 产品简介&#xff1a; 设备同时对扁钢或钢板的宽度和厚度进行即时测量 基本原理 该设备共设置2只二维激光测量传感器和2只激光位移传感器。二维传感器设置在两侧&#xff0c;可根据板材厚…

(2)(2.8) Holybro 900Mhz XBP9X无线电遥测设备

文章目录 前言 1 特点 2 规格 3 电源 4 引脚输出 5 下载 前言 Holybro XBP9X 无线电设备可使用 Digi 免费的 XCTU 软件或通过 Digi 简化的 AT 或 API 命令集轻松进行配置。无线电台采用 256 位 AES 加密技术&#xff0c;可在设备之间安全可靠地传输关键数据。无线电的射…

TCP 三次握手以及滑动窗口

TCP 三次握手 简介&#xff1a; TCP 是一种面向连接的单播协议&#xff0c;在发送数据前&#xff0c;通信双方必须在彼此间建立一条连接。所谓的 “ 连接” &#xff0c;其实是客户端和服务器的内存里保存的一份关于对方的信息&#xff0c;如 IP 地址、端口号等。 TCP 可以…

Ceph篇之利用Prometheus监控ceph服务

一、Ceph内置模块 Ceph manager 内部的模块中包含了 prometheus 的监控模块,并监听在每个 manager 节点的 9283 端口&#xff0c;该端口用于将采集到的信息通过 http 接口向 prometheus 提供数据。 二、监控搭建 1、启用 prometheus 监控模块 ceph mgr module enable promethe…

C++技术要点总结, 面试必备, 收藏起来慢慢看

目录 1. 语言对比 1.1 C 11 新特性 2.2 C 和 C 的区别 2.3 Python 和 C 的区别 2. 编译内存相关 2.1. C 程序编译过程 2.2. C 内存管理 2.3. 栈和堆的区别 2.4. 变量的区别 2.5. 全局变量定义在头文件中有什么问题&#xff1f; 2.6. 内存对齐 2.7. 什么是内存泄露 …

vue中使用canvas给图片绘制水印,即使下载图片也是带水印的

先看效果 话不多说直接上组件 1、Watermark.vue <template><div><canvas ref"canvas" :width"width" :height"height"></canvas></div> </template><script>export default {props: {// 图片地址ur…

Linux命令拓展

一、tr - 字符转换 效果展示&#xff1a; 将小写转换成大写 字符压缩 通式&#xff1a;tr -s 字符删除 通式&#xff1a;tr -d 补集 通式&#xff1a;tr -c 用法&#xff1a;随机密码 二、cut - 提取 通式&#xff1a;cut [选项] 文件 选项&#xff1a; -d&#xff1a;分隔符…

RT-Thread: 串口操作、增加串口、串口函数

说明&#xff1a;本文记录RT-Thread添加串口的步骤和串口的使用。 1.新增串口 官方链接&#xff1a;https://www.rt-thread.org/document/site/rtthread-studio/drivers/uart/v4.0.2/rtthread-studio-uart-v4.0.2/ 新增串口只需要在 board.h 文件中定义相关串口的宏定…

构建未来学堂:在线教育系统开发技术实践

在当今数字化时代&#xff0c;在线教育系统的开发越发显得至关重要。本文将带你深入了解在线教育系统的开发&#xff0c;涉及到关键的技术实践和代码示例。我们将采用现代化技术栈&#xff0c;为未来学堂的搭建提供实用的指南。 技术栈选择 在开始实际的开发之前&#xff0c…

ETL能实现什么流程控制方式?

随着大数据时代的到来&#xff0c;数据处理工具成为各个行业中不可或缺的一部分。运用数据处理工具&#xff0c;能够大幅度帮助开发人员进行数据处理等工作&#xff0c;以及能够更好的为企业创造出有价值的数据。那在使用ETL工具时&#xff0c;我们往往会通过ETL平台所携带的组…

响应式Web开发项目教程(HTML5+CSS3+Bootstrap)第2版 例4-11 HTML5 表单验证

代码 <!doctype html> <html> <head> <meta charset"utf-8"> <title>HTML5 表单验证</title> </head><body> <form action"#" method"get" novalidate>请输入您的邮箱:<input type&q…

训练YOLOv5模型(云端GPU)

Colab 选择GPU 查看配置 ! nvidia-smi上传压缩包并解压 压缩包 -> 解压的文件 !unzip /content/yolov5-5.0.zip -d/content/yolov5进入目标文件夹下 %cd /content/yolov5/yolov5-5.0安装所需包package !pip install -r requirements.txt添加插件-Tensorboard 失败的话…

matlab绘图杂谈-stem函数和plot函数

出发点 今天在论文中看到一副这样的图&#xff0c;它既有曲线&#xff0c;又有点&#xff0c;并且对两者都添加了图例。三条曲线应该是用plot函数绘制的&#xff0c;而target哪个绿色的圆圈&#xff0c;我的理解是用stem函数绘制的。它只是1个点&#xff0c;并且没有竖线&…

qwt直角坐标 画sing(x)/x

cmath的常见函数&#xff1a;qPow()求平方&#xff0c;log(&#xff09;对数10为底 角度转弧度&#xff1a;x(angel/180)*M_PI 图示&#xff1a; 头文件&#xff1a; #ifndef MAINWINDOW_H #define MAINWINDOW_H#include <QMainWindow> #include <qwt_plot.h> #in…

【学术论文写作 笔记03】消融实验(ablation study)写作的行文逻辑

文章目录 一、声明二、行文逻辑三、示例示例一示例二 四、常用短语&#xff08;未完&#xff09; 一、声明 自己总结的&#xff0c;有问题望指正&#xff01; 二、行文逻辑 总述&#xff1a;在什么数据集上测试了关于什么参数或模块的消融实验实验是怎么做的实验结论是什么 …