题意: 给定个矩形的宽和高,求可以得到的矩形的最大面积。
题解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; }