题意:求一个直方图中最大矩形的面积。
很经典的一道问题了吧,可以用单调栈分别求出每个柱子左右两边第一个比它低的柱子(也就相当于求出了和它相连的最后一个比它高的柱子),确定每个柱子的左右边界,每个柱子的高度乘上左右边界的宽度求最大值就行了。
也可以用笛卡尔树上dp的方法搞一搞,即用每个结点权值和所在子树的大小分别表示高度和宽度。(建笛卡尔树的过程也用到了单调栈,作用是维护右链)
单调栈做法:
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int N=1e5+10,inf=0x3f3f3f3f; 5 int a[N],n,sta[N],L[N],R[N],tp; 6 7 int main() { 8 while(scanf("%d",&n)&&n) { 9 a[0]=a[n+1]=-1; 10 for(int i=1; i<=n; ++i)scanf("%d",&a[i]); 11 sta[tp=0]=0; 12 for(int i=1; i<=n; ++i) { 13 for(; a[sta[tp]]>=a[i]; --tp); 14 L[i]=sta[tp]+1,sta[++tp]=i; 15 } 16 sta[tp=0]=n+1; 17 for(int i=n; i>=1; --i) { 18 for(; a[sta[tp]]>=a[i]; --tp); 19 R[i]=sta[tp]-1,sta[++tp]=i; 20 } 21 ll ans=0; 22 for(int i=1; i<=n; ++i)ans=max(ans,(ll)a[i]*(R[i]-L[i]+1)); 23 printf("%lld\n",ans); 24 } 25 return 0; 26 }
笛卡尔树做法:
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int N=1e5+10,inf=0x3f3f3f3f; 5 int n,a[N]; 6 struct Cartesian { 7 static const int N=1e5+10; 8 int ls[N],rs[N],val[N],siz[N],sta[N],tp,tot; 9 int newnode(int x) {int u=tot++; ls[u]=rs[u]=siz[u]=0,val[u]=x; return u;} 10 void build(int* a,int n) { 11 tot=0,newnode(0),sta[tp=0]=newnode(-1); 12 for(int i=0; i<n; ++i) { 13 int u=newnode(a[i]); 14 for(; val[sta[tp]]>=val[u]; --tp); 15 ls[u]=rs[sta[tp]],rs[sta[tp]]=u; 16 sta[++tp]=u; 17 } 18 } 19 void dfs(int u=1) { 20 if(!u)return; 21 dfs(ls[u]),dfs(rs[u]); 22 siz[u]=siz[ls[u]]+siz[rs[u]]+1; 23 } 24 } cart; 25 26 int main() { 27 while(scanf("%d",&n)&&n) { 28 for(int i=0; i<n; ++i)scanf("%d",&a[i]); 29 cart.build(a,n); 30 cart.dfs(); 31 ll ans=0; 32 for(int i=0; i<cart.tot; ++i)ans=max(ans,(ll)cart.siz[i]*cart.val[i]); 33 printf("%lld\n",ans); 34 } 35 return 0; 36 }