题意: 给定个矩形的宽和高,求可以得到的矩形的最大面积。
题解1:
本题一眼看上去就是笛卡尔树的题,可惜笛卡尔树当时学到半路放弃了。回想过来笛卡尔树是由单调栈延伸过来的,所以考虑能不能用单调栈瞎搞。
本题的难点在于如何处理一定宽度和高构成的矩形面积,即可能更长的宽度和较短的高度也会构成更大的面积。
考虑单调栈,由于短板决定高度,所以要构造一个单调递增的栈。
- 当
时,直接入栈,最后的栈一定是单调递增的,所以对于栈内每个元素,出栈时其必然比之前的元素高度低,所以可以直接叠加他们的宽度计算。
- 当
时,短板决定高度,所以要将当前栈的所有元素高度全部切成不高于
才能继续发挥作用。切成
的高度相当于给
增加宽度,所以对于栈内每个元素,出栈时其必然比之前的元素高度低,所以可以直接叠加他们的宽度计算。
- 最后得到的单调递增栈,依然是:出栈时其必然比之前的元素高度低,所以可以直接叠加他们的宽度计算。这里的技巧是增加一个
,高度为
,使得栈中的元素被迫直接出栈。
注意要开long long
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e6 + 10;
struct Node{
int h, w;
}p[N];
int n;
Node stk[N];
int top;
int main()
{
scanf("%d", &n);
for(int i = 1; i <= n; ++i) scanf("%d", &p[i].w);
for(int i = 1; i <= n; ++i) scanf("%d", &p[i].h);
p[n + 1] = {0, 0};
ll res = 0;
for(int i = 1; i <= n + 1; ++i) {
if(top == 0 || stk[top].h < p[i].h) stk[++top] = p[i];
else {
if(stk[top].h == p[i].h) stk[top].w += p[i].w;
else {
//切成p[i].h高度
int len = 0;
while(top > 0 && stk[top].h > p[i].h) {
len += stk[top].w;
res = max(res, 1ll * stk[top].h * len) ;
--top;
}
while(top > 0 && stk[top].h == p[i].h) {
len += stk[top].w;
--top;
}
p[i].w += len;
stk[++top] = p[i];
}
}
}
printf("%lld\n", res);
return 0;
} 题解2:
学习了https://blog.nowcoder.net/n/e1d2ba3f75284f678e546374ce5e569b
后,理解了点笛卡尔树。
本题直观做法就是以每个矩形高度为标准,向左向右得到最长的宽度。
那么建立小根堆笛卡尔树后,根的左右子树中每个元素的高度都大于等于根的元素高度,从根结点开始,即可求得左右子树加上自身可以得到的最大宽度。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e6 + 10;
int ls[N], rs[N];
int stk[N], top;
ll res = 0;
struct Node{
int h, w;
}p[N];
int n;
void build() {
top = 0;
for(int i = 1; i <= n; ++i) {
int temp = top;
while(p[stk[temp]].h > p[i].h) --temp;
if(temp) rs[stk[temp]] = i;
if(temp < top) ls[i] = stk[temp + 1];
stk[++temp] = i;
top = temp;
}
}
int dfs(int u) {
if(!u) return 0;
int sz = p[u].w;
sz += dfs(ls[u]);
sz += dfs(rs[u]);
res = max(res, 1ll * sz * p[u].h);
return sz;
}
int main()
{
scanf("%d", &n);
for(int i = 1; i <= n; ++i) scanf("%d", &p[i].w);
for(int i = 1; i <= n; ++i) scanf("%d", &p[i].h);
build();
dfs(stk[1]);
printf("%lld\n", res);
return 0;
} 
京公网安备 11010502036488号