单调队列——定长区间最值问题

本文同步发表于我的 洛谷博客

一、引入

1.1 定长滑窗问题:

给出一列 n n n 个正整数,和一个固定长度为 k k k 的滑动窗口, 从左到右在数列中滑动这个窗口,找到数列中每个窗口内的最大值。

即对于给定数列 A 1 ∼ A n A_1\sim A_n A1An ( 1 ≤ n ≤ 1 0 7 ) (1\le n\le 10^7) (1n107),求每一个 f i = min ⁡ j = i − k + 1 i A j f_i=\min\limits_{j=i-k+1}^{i}A_j fi=j=ik+1miniAj

二、数据维护

2.0 线段树,RMQ

这两者与 2.1 都是 Θ ( n log ⁡ n ) \Theta(n\log n) Θ(nlogn) 级别的复杂度,且代码量较大,因此略过。

2.1 多重集

2.1.1 简介

multiset 是 STL 容器中的一种,中文名为多重集。多重集是按照特定顺序存储元素的容器,其中多个元素可以具有相等的值。

其底层数据结构为红黑树,是一种高度平衡的二叉搜索树,因此插入,搜索和删除都是 Θ ( log ⁡ n ) \Theta (\log n) Θ(logn) 的复杂度,而对于根节点的访问则是 Θ ( 1 ) \Theta(1) Θ(1) 的。

2.1.2 解决方法

每一次插入新的元素,并删除旧元素。由于 multiset 自动按从小到大进行排序,因此一段定长区间的最大值即为 *s.rbegin()

2.1.3 代码

multiset<int,greater<int> > s; //从大到小排序,不去重 
inline void Multiset(){
   
	scanf("%d%d",&n,&k);
	for(int i=1;i<=n;i++) scanf("%d",&x[i]);//input
	
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,关于用 C 语言建立笛卡尔树求解区间最值问题,我可以给你一些基本的思路和代码实现。 首先,笛卡尔树是带权值的树,其性质由下面的定理给出: 定理1:一个序列可以对应唯一的一棵笛卡尔树。 定理2:设在笛卡尔树上节点 u 和 v 的先后顺序为“按下标增大的顺序,在这个前提下按权值减小的顺序”,则 u 到 v(包括 u 和 v)路径上的点在原序列中构成了一个区间。 基于这两个定理,我们就可以使用笛卡尔树来解决区间最值问题,其基本思路如下: 1. 输入一个序列 a[N],构建对应的笛卡尔树。 2. 对于每个节点 u,记录其子树中最小值或最大值(根据具体问题而定)。 3. 对于每个询问,找到笛卡尔树上 u 和 v 两个节点,使得它们对应的区间包含询问区间 [L,R],那么 [L,R] 中的最值就是从 u 到 v 路径上的最小值或最大值(可以使用 st 表等数据结构进行维护)。 下面是用 C 语言实现笛卡尔树的基本代码,可以参考一下: struct Node { int val, idx; int fa, ch[2]; } tree[N]; int root, idx; int build(int l, int r) { // 构建笛卡尔树并返回根节点编号 if (l > r) return -1; int x = l; for (int i = l + 1; i <= r; i++) if (tree[i].val < tree[x].val) x = i; tree[x].ch[0] = build(l, x - 1); tree[x].ch[1] = build(x + 1, r); if (tree[x].ch[0] != -1) tree[tree[x].ch[0]].fa = x; if (tree[x].ch[1] != -1) tree[tree[x].ch[1]].fa = x; return x; } 现在我回答了你的问题,如果您有任何其他问题,可以随时问我。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值