HDU 1506. Largest Rectangle in a Histogram 题解 笛卡尔树

题目链接:https://acm.hdu.edu.cn/showproblem.php?pid=1506

题目大意:

找 直方图中的最大矩形面积。

解题思路:

具体地,我们把下标 \(i\) 作为键值 \(k\),\(h_i\) 作为键值 \(w\)。满足小根堆性质,构建一棵 \((i, h_i)\) 的笛卡尔树。
这样我们枚举每个节点 \(u\),把 \(w_u\)(即节点 \(u\) 的高度 \(h\))作为最大矩形的高度。由于我们建立的笛卡尔树满足小根堆性质,因此 \(u\) 的子树内的所有节点的高度都大于等于 \(u\)。而我们又知道 \(u\) 子树内的下标是一段连续的区间。
于是我们只需要知道子树的大小,就可以算出这个区间以 \(w_u\) 为高度的最大矩形面积。用每一个点计算出来的值更新答案即可。
显然,这个过程可以通过一次 DFS(深度优先搜索) 完成,因此时间复杂度是 \(\mathcal{O}(n)\) 的。

示例程序:

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int maxn = 1e5 + 5;

int n, a[maxn], ls[maxn], rs[maxn], sz[maxn];
ll ans;
stack<int> stk;

void build_tree() {
	while (!stk.empty())
		stk.pop();
	for (int i = 1; i <= n; i++) {
		int last = 0;
		while (!stk.empty() && a[stk.top()] > a[i]) {
			last = stk.top();
			stk.pop();
		}
		if (!stk.empty())
			rs[stk.top()] = i;
		if (last)
			ls[i] = last;
		stk.push(i);
	}
}

void dfs(int u) {
	sz[u] = 1;
	if (ls[u]) dfs(ls[u]), sz[u] += sz[ ls[u] ];
	if (rs[u]) dfs(rs[u]), sz[u] += sz[ rs[u] ];
	ans = max(ans, 1ll * a[u] * sz[u]);
}

int main() {
	while (~scanf("%d", &n) && n) {
		for (int i = 1; i <= n; i++)
			scanf("%d", a+i);
		fill(ls+1, ls+n+1, 0);
		fill(rs+1, rs+n+1, 0);
		build_tree();
		int rt;
		do {
			rt = stk.top();
			stk.pop();
		} while (!stk.empty());
		ans = 0;
		dfs(rt);
		printf("%lld\n", ans);
	}
	return 0;
}
posted @ 2026-09-02 11:09  quanjun  阅读(9)  评论(0)    收藏  举报