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;
}
浙公网安备 33010602011771号