
动态区间最值(RMQ)——线段树
发布日期:2021-05-07 02:27:39
浏览次数:20
分类:精选文章
本文共 3607 字,大约阅读时间需要 12 分钟。
建树
a a a数组为初始数组, t r e e tree tree数组为树
typedef long long ll;const int inf = 0x7fffffff;const int maxn = 2e5 + 10;int a[maxn];int tree[maxn << 2], lz[maxn << 2];
建树函数
和普通线段树唯一的区别就是更新时取左右子树的最值
void build(int i, int l, int r) { //i传入1 if (l == r) { tree[i] = a[l]; return; } int mid = (l + r) >> 1, k = i << 1; build(k, l, mid); build(k | 1, mid + 1, r); tree[i] = max(tree[k], tree[k | 1]);}
单点修改
函数功能:将位置 x x x的值修改为 y y y
因为没有用结构体保存区间的左右边界 l , r l,r l,r,因此需要传入修改的总区间 [ l , r ] = [ 1 , n ] [l,r] = [1,n] [l,r]=[1,n]
void update(int i, int l, int r, int x, int y) { if (l == r) { tree[i] = y; return; } int mid = (l + r) >> 1, k = i << 1; if (x <= mid) update(k, l, mid, x, y); else update(k | 1, mid + 1, r, x, y); tree[i] = max(tree[k], tree[k | 1]);}
区间加法
懒惰标记
使用数组 l z lz lz记录向子区间都加的值, p u s h d o w n pushdown pushdown时只需要将子节点的值和标记都加上父节点的标记,然后清空父节点的标记。
void pushdown(int i) { if (lz[i]) { int k = i << 1; tree[k] += lz[i], tree[k | 1] += lz[i]; lz[k] += lz[i], lz[k | 1] += lz[i], lz[i] = 0; }}
区间加法
将区间 [ x , y ] [x,y] [x,y]都加上 v a l val val。
void add(int i, int l, int r, int x, int y, int val) { if (l == x && r == y) { tree[i] += val, lz[i] += val; return; } pushdown(i); int mid = (l + r) >> 1, k = i << 1; if (x > mid) add(k | 1, mid + 1, r, x, y, val); else if (y <= mid) add(k, l, mid, x, y, val); else add(k, l, mid, x, mid, val), add(k | 1, mid + 1, r, mid + 1, y, val); tree[i] = max(tree[k], tree[k | 1]);}
区间查询
函数功能:查询区间 [ x , y ] [x,y] [x,y]的最值。
有三种情况:
- 如果被修改区间完全在左区间
- 如果被修改区间完全在右区间
- 如果都不在,就要把修改区间分解成两块,分别往左右区间递归
int query(int i, int l, int r, int x, int y) { if (x <= l && y >= r) return tree[i]; pushdown(i); int mid = (l + r) >> 1, k = i << 1; if (y <= mid) return query(k, l, mid, x, y); else if (x > mid) return query(k | 1, mid + 1, r, x, y); return max(query(k, l, mid, x, y), query(k | 1, mid + 1, r, x, y));}
简单模板
typedef long long ll;const int inf = 0x7fffffff;const int maxn = 2e5 + 10;int a[maxn];int tree[maxn << 2], lz[maxn << 2];inline int max(int a, int b) { return a > b ? a : b; }void build(int i, int l, int r) { if (l == r) { tree[i] = a[l]; return; } int mid = (l + r) >> 1, k = i << 1; build(k, l, mid); build(k | 1, mid + 1, r); tree[i] = max(tree[k], tree[k | 1]);}void update(int i, int l, int r, int x, int y) { if (l == r) { tree[i] = y; return; } int mid = (l + r) >> 1, k = i << 1; if (x <= mid) update(k, l, mid, x, y); else update(k | 1, mid + 1, r, x, y); tree[i] = max(tree[k], tree[k | 1]);}void pushdown(int i) { if (lz[i]) { int k = i << 1; tree[k] += lz[i], tree[k | 1] += lz[i]; lz[k] += lz[i], lz[k | 1] += lz[i], lz[i] = 0; }}void add(int i, int l, int r, int x, int y, int val) { if (l == x && r == y) { tree[i] += val, lz[i] += val; return; } pushdown(i); int mid = (l + r) >> 1, k = i << 1; if (x > mid) add(k | 1, mid + 1, r, x, y, val); else if (y <= mid) add(k, l, mid, x, y, val); else add(k, l, mid, x, mid, val), add(k | 1, mid + 1, r, mid + 1, y, val); tree[i] = max(tree[k], tree[k | 1]);}int query(int i, int l, int r, int x, int y) { if (x <= l && y >= r) return tree[i]; pushdown(i); int mid = (l + r) >> 1, k = i << 1; if (y <= mid) return query(k, l, mid, x, y); else if (x > mid) return query(k | 1, mid + 1, r, x, y); return max(query(k, l, mid, x, y), query(k | 1, mid + 1, r, x, y));}
发表评论
最新留言
做的很好,不错不错
[***.243.131.199]2025年04月01日 04时33分51秒
关于作者

喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
WinUI 3 Preview 3 发布了,再一次试试它的性能
2021-05-09
使用命令把SpringBoot项目打包成可运行的jar包(简洁,操作性强)
2021-05-09
List数组排序
2021-05-09
VMware vSphere 离线虚拟机安装 BIND 9
2021-05-09
说说第一份工作
2021-05-09
dojo/request模块整体架构解析
2021-05-09
dojo/aspect源码解析
2021-05-09
Web性能优化:What? Why? How?
2021-05-09
Javascript定时器学习笔记
2021-05-09
dojo的发展历史
2021-05-09
Python存储系统(Redis)
2021-05-09
C语言指针收藏
2021-05-09
C#搞个跨平台的桌面NES游戏模拟器
2021-05-09
手把手教你安装Eclipse最新版本的详细教程 (非常详细,非常实用)
2021-05-09
《带你装B,带你飞》pytest成魔之路4 - fixture 之大解剖
2021-05-09
互联网App应用程序测试流程及测试总结
2021-05-09
根据轨迹分析出用户家在哪
2021-05-09
PostgreSQL查询表名称及表结构
2021-05-09
linux中使用awk命令
2021-05-09
如何使用google搜索?
2021-05-09