题目:http://acm.hdu.edu.cn/showproblem.php?pid=1506
题意:给定一个统计直方图,n个矩形条,每个矩形条宽1,高0-10^9,求最大矩形面积。
分析:天然的笛卡尔树,以输入的顺序为第一关键字,矩形条的高为第二关键字建立一颗笛卡尔树,并且是一个小堆。那么从
树根开始后序遍历整颗树,在节点处结算一次保存最大值。建树O(n),遍历树也是O(n),所以总的时间复杂度也是O(n)。
首先笛卡尔树是一个二叉排序树,那么以输入顺序作为二叉排序树的关键字,所建出来的树保证以任意节点为根的子树的所有
节点是连续的,然后笛卡尔树以矩形条的高度为关键字又有堆的性质,而这题的关键不就正是要找连续的矩形条,使总面积最
大,而决定大矩形高度的就是每个小矩形条的最小高度!那么我们维护一个小堆即可,这样在每个节点处就保证以该节点为根
的子树所能构成的最大矩形就是该节点的高度*该子树的大小。
#include <iostream>
#include <string.h>
#include <stdio.h>
using namespace std;
typedef long long LL;
const int N=100005;
const LL INF=(LL)1<<62;
struct node
{
LL fix;
int pre,l,r;
void clear()
{
pre=l=r=0;
}
};
node T[N];
LL ans;
void Init(int n)
{
for(int i=0;i<=n;i++)
T[i].clear();
T[0].fix=-INF;
}
int Build(int n)
{
for(int i=1; i<=n; i++)
{
int j=i-1;
while(T[j].fix>T[i].fix)
j=T[j].pre;
T[i].l=T[j].r;
T[j].r=i;
T[i].pre=j;
}
return T[0].r;
}
int dfs(int cur)
{
if(cur==0) return 0;
LL num=dfs(T[cur].l)+dfs(T[cur].r)+1;
LL tmp=num*T[cur].fix;
if(tmp>ans) ans=tmp;
return num;
}
void print(int cur)
{
if(cur==0) return;
printf("%d\n",T[cur].fix);
print(T[cur].l);
print(T[cur].r);
}
int main()
{
int n;
while(~scanf("%d",&n),n)
{
Init(n);
for(int i=1;i<=n;i++)
scanf("%I64d",&T[i].fix);
int root=Build(n);
ans=0;
dfs(root);
printf("%I64d\n",ans);
}
return 0;
}