直方图中最大的矩形(笛卡尔树解决)

喵帕斯!

我们来换种思路。


题目大意#

略略略~

分析#

假设我们已经会单调栈了,(如果不会可以去看看其他题解),所以单调栈的思想这里我就不再说了。

考虑使用笛卡尔树解决该问题。

什么是笛卡尔树?#

笛卡尔树是一种特定的二叉树数据结构,可由数列构造,在范围最值查询、范围top kth查询等问题上有广泛应用。它具有堆的有序性,中序遍历可以输出原数列。笛卡尔树结构由Vuillmin(1980)在解决范围搜索的几何数据结构问题时提出。从数列中构造一棵笛卡尔树可以线性时间完成,需要采用基于的算法来找到在该数列中的所有最近小数。(百度百科)

人话翻译如下:

概念:笛卡尔树是一种二叉树,每个节点有两个值keyvalue

性质

  1. 堆的性质。笛卡尔树的树根是这一子树中key值最小(大)的元素,父节点的键值均小于(或大于)其左右子节点的键值,可以这样递归地弄下去。
  2. 树的中序遍历即为原数组序列。

如图,这样就是一棵原序列的笛卡尔树。(可以结合之前讲的看一下)

构造笛卡尔树#

一般,我们规定按key为第一关键字排序,(很多时候,key值即为数组下标)。

用单调栈实时维护当前树中的最右链,模仿递归建树的过程(建虚树也是这种思想啊)。

以维护小根堆为例,在以key值增序排序后,我们考虑插入一个新点i,它的值为V

我们从栈顶出发,一直找到第一个位置posvalue小于V,因为是小根堆,所以要保证ipos的儿子,又因为当前的key值大于之前出现过的所有值,所以ipos的右儿子,需要把原来pos的右儿子变成i的左儿子,代码注释里也有。

然后O(n)完成对笛卡尔树的构建。

本题的解决#

key值就是数组下标,无需排序,直接高度建树。

然后直接在树上从根节点往下走,每个节点的高度确定,所能扩展的长度即为它的子节点的区间长度,每走到一个节点就去个maxO(n)的遍历,总时间复杂度也是O(n)的(虽然有2这个常数TAT)。

注意多组数据的话,及时在回溯时初始化。

代码#

Copy
#include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> using namespace std; #define Re register #define ll long long const int N = 100000 + 5; const int INF = 0x7fffffff; inline int read() { int res = 0; bool f = 0; char ch = getchar(); while (ch < '0' || ch > '9') { if (ch == '-') f = 1; ch = getchar(); } while (ch <= '9' && ch >= '0') { res = (res << 3) + (res << 1) + ch - '0'; ch = getchar(); } return f ? (~ res + 1) : res; } ll ans; int n, a[N]; inline ll max(ll a, ll b) { return a < b ? b : a; } struct Cartesian_Tree { int sta[N], top, ls[N], rs[N], root; inline void init() { top = 0; for (Re int i = 1;i <= n; ++i) { /* 用栈来维护最右链,一直找到一个位置pos的a值会小于当前a值 */ while (top && a[sta[top]] >= a[i]) ls[i] = sta[top--]; /* 因为是小根堆,所以要保证i是pos的儿子,又因为当前的key值大于之前出现 过的所有值,所以i是pos的右儿子,需要把原来pos的右儿子变成i的左儿子 */ if (top) rs[sta[top]] = i; sta[++top] = i; } root = sta[1]; } inline int dfs(int x) { if (!x) return 0; int res = dfs(ls[x]) + dfs(rs[x]) + 1; ls[x] = 0, rs[x] = 0; ans = max(ans, (ll)res * a[x]); return res; } }CT; int main(){ while (1) { n = read(); if (n == 0) break; for (Re int i = 1;i <= n; ++i) a[i] = read(); CT.init(); ans = 0; CT.dfs(CT.root); printf("%lld\n", ans); } return 0; }
posted @   SilentEAG  阅读(498)  评论(0编辑  收藏  举报
编辑推荐:
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示
CONTENTS