神秘数据结构手法之区间 LIS

news/2025/10/31 22:37:14/文章来源:https://www.cnblogs.com/gsc0618china/p/19181395

给定 \(1\sim n\) 的排列,\(q\) 次询问,每次查询区间 \([l,r]\) 内的最长上升子序列长度。

\(n \leq 10^5\)

这里只讨论排列的情况,如果不是排列,也容易通过重新编号变成在 LIS 上等价的一排列。

\(O(n\sqrt{n}\ \mathrm{log}\ n+q\ \mathrm{log}\ n)\)

首先对于问题的关键在 LIS 的刻画方法上,常见的方法有 dp二分贪心。dp 的做法看起来没有什么优化的空间,尝试使用 二分贪心 的方法。

首先回顾一下二分贪心求 LIS 的过程,它是维护一个集合 \(S\),每次在末尾新加入一个数时,在 \(S\) 中找到最小的大于它的数并替换,如果没有则直接插入。

代入到这个区间的问题上来,我们考虑令 \(S_{i,j}\) 表示从 \(i\) 顺序扫描到 \(j\) 结束后的集合 \(S\)。关于这个集合 \(S\) 有两个关键性质:

  1. \(S_{i+1,j} \subseteq S_{i,j}\)

  2. \(||S_{i+1,j}|-|S_{i,j}|| \leq 1\)

第二条性质比较显然,可以考虑从 \(j\) 往前扫,\(|S_{i,j}|\)\(|S_{i+1,j}|\) 唯一可能产生变化的地方在于 \(S_{i,j}\) 拥有在最后插入的一个 \(a_i\),然而 \(a_i\) 最多使得 LIS 长度变化 1。

对于第一条性质做一个说明,可以发现 \(S_{i,j}\)\(S_{i+1,j}\) 的区别之处就是 \(S_{i,j}\) 在最开始比 \(S_{i+1,j}\) 多放一个 \(a_i\)\(S_{i+1,j}\) 初始则是空的,然后两个 \(S\) 都是正常插入 \(a_{i+1},a_{i+2},...,a_j\) 了。因此我们讨论 \(a_i\) 是否被替换了,如果 \(a_i\) 被替换了就毫无影响,那么就相当于是 \(a_{i+1},a_{i+2},...,a_j\) 按照上面的流程做一遍,因此 $S_{i,j}=S_{i+1,j}。如果 \(a_i\) 没被替换,那么显然对于 \(a_{i+1},a_{i+2},...,a_j\) 没有数小于 \(a_i\),即 \(a_i\) 最小,那么 \(a_i\) 显然影响不到后面的操作,因此 \(S_{i,j}={a_i} \cup S_{i+1,j}\)

综上,两条性质均已被证明。我们继续回到原问题。

第一条性质说明了一件事情,就是我们可以认为 \(S_{i,j}\) 对于一个固定的 \(j\) 而言,从 \(S_{1,j}\) 扫到 \(S_{j,j}\) 的过程就是每次可以删除至多一个数,所以对于 \(a_1,a_2,...,a_j\) 每个数来说,它在 \(S_{i,j}\) 出现的都是一个 \(i\) 的前缀,尝试对于所有 \(j\),维护它的 \(a_i(i \leq j)\) 对应的前缀 \(p_{a_i}\)(注意:这里 \(p_x\) 表示值为 \(x\) 的位置对应的前缀,\(x\) 并非位置),那么如果我们把所有询问 \((l,r)\) 挂在 \(r\) 上,那么就是要求 \(j=r\) 时有多少个 \(p_i \geq l\)

考虑对 \(j\) 做扫描线,当 \(j \to j+1\) 时维护 \(p\) 数组的变化,对于新加入的 \(v=a_{j+1}\),显然有 \(p_{v}=j+1\),因为不管前面的 \(S\) 长啥样,\(a_{j+1}\) 一定会替换掉其中一个使得 \(a_{j+1}\) 存在于 \(S\)。对于之前的 \(p_x\),若 \(x<v\),那么显然 \(v(a_{j+1})\) 的加入不会产生影响,因此我们只考虑 \(x>v\)\(p_x\)

对于 \(p_{v+1}\) 它不管之前在不在,一定会被 \(v\) 替换掉,所以直接 \(p_{v+1}=0\)。对于 \(p_{v+2}\),只有当插入 \(a_{j+1}\) 的时候 \(v+1\)\(S\) 中出现,才能让 \(v+1\)\(v+2\) 挡一刀使得 \(v+2\) 活着,因此只有在 \(\mathrm{min}(p_{v+1},p_{v+2})\) 这个前缀 \(v+2\) 能活着,也就是当 \(p_{v+2}>p_{v+1}\) 时,会有 \(p_{v+2}=p_{v+1}\),否则不变。

模拟上面的过程,可以写出下面形式的代码:

p[v]=j+1,now=0;
for(int i=v+1;i<=n;i++)if(p[i]>now)swap(p[i],now);

首先考虑如果不是对 \(v+1\) 这个后缀操作,而是从 \(1\) 扫到 \(n\),即下面这个代码:

p[v]=j+1,now=0;
for(int i=1;i<=n;i++)if(p[i]>now)swap(p[i],now);

那么因为我们只关注有多少个 \(p_x \geq l\),因此我们只关系 \({p_i}\) 这个可重集。考虑执行上面那个代码对 \({p_i}\) 的影响,可以发现是若 \(now>\mathrm{max}\{p_i\}\),则不影响,否则会把最大值替换成 \(now\)。为什么是这样呢?考虑第一个满足 \(p_i>now\) 的位置,那么这个位置就会被换成 \(now\),然后 \(now\) 变成这个位置然后继续往后放,第二个也是如此,以此类推。如果我们设被替换的位置序列为 \(b_1,b_2,...,b_m\),那么最终它们的值就是 \(now,p_1,p_2,...,p_{m-1}\),对于整个可重集也就是把 \(a_m\) 替换成 \(now\),而 \(a_m\) 显然是整个数组的最大值,故此说明。这个过程可以用堆来维护。

现在思考 \(i=v+1,v+2,...,n\) 来操作时的做法。这里是一个类似于对区间操作的事情,如果我们还对于整个 \(\{p_i\}\) 的可重集考虑的话,因为可重集是个集合,关注的是整体的变化,没法记位置所以肯定不能再考虑整个了。但是我们可以分块,每个块内维护一个堆,记录整个块的可重集信息。对于 \(v+1 \sim n\) 的整块,从左到右扫描,每次维护一个当前的 \(now\)。对于当前扫到的块,如果 \(now<\mathrm{max}\{p_i\}\),那么就把 \(\mathrm{max}\{p_i\}\) 替换成 \(now\),并把 \(now=\mathrm{max}\{p_i\}\),否则不操作,做完之后扫下去。

整块知道怎么做了以后看散块,如果我们知道这个散块内每个元素是啥,那么就能直接模拟一遍了,然鹅我们对于块维护的都是整体信息,所以肯定还得弄出点新的东西来维护。我们考虑对于一个块,假设我们知道这个块被哪些 \(now\) 更新过(把整个块扫过一遍),能否还原出每个数呢?确定数的顺序应该和更新的顺序一致,从块内第一个元素开始还原。假设这个块是被 \(now:\{x_1,x_2,...,x_m\}\) 更新的(我们可以对于每个块记录标记,维护它被哪些 \(now\) 更新过),那么第一个元素一定是被最小的那个 \(x\) 更新,也就是说它的值就是 \(x\) 中的最小者,然后这个最小者在往后更新的时候因为和第一个元素 \(\mathrm{swap}\) 了,所以它在后面更新的时候值就是 \(p_{blk_1}\)(第一个元素原本值)了,也就是说要把 \(x\) 中最小值替换成 \(p_{blk_1}\),这个可以发现也是可以用堆维护的。当整个块处理完以后,因为 \(p\) 也更新了,所以得把标记清空。

这样就得到了一个 \(O(n\sqrt{n}\ \mathrm{log}\ n+q\ \mathrm{log}\ n)\) 的做法,可以通过。

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

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

相关文章

软考九

软考九Posted on 2025-10-31 22:31 心默默言 阅读(0) 评论(0) 收藏 举报1. 系统设计2. 数据流图

[该退役了]

[该退役了]好了,最近本来说找队友的,结果教练给我找了上次的那个谁 反正是直接导致黑化的决定性因素,也有记录 但是这个人好像是教练的掌中宝啊,不组队还说我伤害了她,然后就宣告不管我了, 简单讲就是这一波是彻…

逆向基础--汇编语言介绍(003)

逆向基础--汇编语言介绍(003)一.前言汇编语言是直接工作在硬件上的一门编程语言,是除了机器语言外的最低层的编程语言了,学习汇编可以帮助我们更加深入的了解cpu,内存等硬件的工作原理。汇编语言和机器语言一般都是一…

文档抽取技术的实现原理及其在法律行业的应用价值分析

想象一位律师,面对堆积如山的案卷:数千页的交易合同、错综复杂的证据材料、浩如烟海的裁判文书。他必须从中精准找出关键条款、锁定矛盾陈述、串联案件事实。这曾是法律工作的常态,耗时耗力且充满疏漏风险。而今,文…

【算法导论】2分治法

【算法导论】2分治法二分查找 using System;class BinarySearch {// 分治法实现二分查找public static int Search(int[] arr, int target, int left, int right){// 基本情况:查找范围为空if (left > right)retur…

c++写得多不如写得少,同样的逻辑写的多报错逆天

#include<iostream> #include<cstdio> #include<cstring> #include<string> #include<cmath> #include<algorithm> #include<vector> #include<map> #include<uno…

整理数学数据结构

#include<bits/stdc++.h>using namespace std;const int N = 1e5 + 5;//树 struct tree{int to[N << 1], nxt[N << 1], hd[N], idx, w[N << 1];void add(int u, int v, int val) { to[++ idx]…

viewerjs+vue3 using typescript

安装包npm install v-viewer viewerjs npm i fontawesome-4.7 npm install @fortawesome/fontawesome-svg-core npm install @fortawesome/free-solid-svg-icons npm install @fortawesome/vue-fontawesome@prerelease…

题解:B4207 [常州市赛 2021] 战士

题解:B4207 [常州市赛 2021] 战士 前言 题目传送门 思路讲解 思路其实很好想,因为怪物的攻击是固定的,所以战士的死亡时间也是固定的,我们就需要通过计算战士每次死亡前能造成的最大伤害如果可以击败怪物,那就直接…

最小二乘问题详解7:正则化最小二乘

本文系统阐述了正则化最小二乘(岭估计)的动机、理论推导、求解方法与数值实例,揭示其通过L2惩罚项改善病态问题和过拟合的机制。1. 引言 在之前的文章《最小二乘问题详解4:非线性最小二乘》、《最小二乘问题详解5:…

什么是重组蛋白?

重组蛋白的定义与基本概念 重组蛋白是指通过基因工程技术,将外源基因导入宿主细胞,利用细胞的生物合成系统表达产生的蛋白质分子。这项技术的核心在于基因重组,即通过人工手段将编码目标蛋白的DNA序列插入表达载体,…

Day9文字颜色

<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0">…

代码大全2{3}

高质量代码要易理解、易扩展。书中关于类设计、接口定义的原则,结合具体示例讲解如何降低代码耦合度,逻辑清晰且实用性强。“单一职责原则” 避免 “万能类 / 函数”带来的问题,划分职责界限,比如一个 “用户管理”…

work3

这个作业属于哪个课程:https://edu.cnblogs.com/campus/fzu/gjyycx 这个作业要求在哪里: https://edu.cnblogs.com/campus/fzu/gjyycx/homework/13574 学号:102500331 姓名:余武 一.书本第4章4.8编程练习题目中的第…

25.10.31

AGC001D 很早之前看到一度怀疑是错题,然后今天发现我看错题了,原来是说这个序列只包含一种元素啊…… 一个 \(l\) 长的回文串定下了 \(\frac{l}{2}\) 的等价关系,可以视作连边,于是转化出图论模型。 考虑无解是为什…

关于计数

随时施工( 不欢迎来看感觉必须开一个记录计数trick的专栏了,md计数题的式子太e心了(((((

游记2

等出分了,进NOIP了写。

JSON Web Token安全漏洞实战:无需确认令牌验证邮箱与密码重置

本文详细介绍了如何通过篡改JSON Web Token实现邮箱验证绕过、密码重置和账户接管,包含具体的技术操作步骤和漏洞利用方法,展示了JWT在未正确验证签名时的安全风险。玩转JSON Web Token:乐趣与收益并存 大家好,希望…

软考-关于《网络安全法》修订相关题目(10道)

根据2025年10月28日通过的《网络安全法》修改决定,该修正案将于何时正式施行?A. 2025年11月1日 B. 2025年12月1日 C. 2026年1月1日 D. 2026年3月1日 答案:C 解析:文章明确指出"自2026年1月1日起施行"。新…

【算法初步】1插入排序

【算法初步】1插入排序using System;class InsertionSortExample {static void Main(){// 测试数组int[] array = { 12, 11, 13, 5, 6 };Console.WriteLine("排序前的数组:");PrintArray(array);// 执行插入…