题目: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;
}