题目大意:给定一张柱形图,每个柱高度不一样,但是宽度都一样,需要求出一个矩形面积的最大值,这个矩形别柱形图所围成的图形所覆盖;
题目解析:对于每个柱,假定以他的高作为高,那么就需要求出尽可能靠左和靠右的使得高度大于那个;这就用到区间了,直接线段树,节点保存区间内的最小值;枚举每个元素的时候,求最左和最右的时候,可以二分,因为区间是具有单调性的,这样o(n*logn*logn)正好过。
AC代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;
typedef long long ll;
const int maxn=60010;
const int inf=0x3fffffff;
int val[maxn<<2],n;
ll a[maxn];
void pushup(int rt)
{
val[rt]=min(val[rt<<1],val[rt<<1|1]);
}
void build(int l,int r,int rt)
{
if(l==r)
{
scanf("%d",&val[rt]);
a[l]=val[rt];
return ;
}
int m=(l+r)>>1;
build(lson);
build(rson);
pushup(rt);
}
int query(int le,int ri,int l,int r,int rt)
{
if(le<=l&&ri>=r) return val[rt];
int m=(l+r)>>1;
int ans=inf;
if(m>=le) ans=min(ans,query(le,ri,lson));
if(m<ri&&val[rt<<1|1]<ans) ans=min(ans,query(le,ri,rson));
return ans;
}
int find_left(int pos,int data)
{
int l=1,r=pos,ans=0;
while(l<=r)
{
int m=(l+r)>>1;
int temp=query(m,pos,1,n,1);
if(temp>=data)
{
ans=m;
r=m-1;
}
else
{
l=m+1;
}
}
return ans;
}
int find_right(int pos,int data)
{
int l=pos,r=n,ans=0;
while(l<=r)
{
int m=(l+r)>>1;
int temp=query(pos,m,1,n,1);
if(temp>=data)
{
ans=m;
l=m+1;
}
else
{
r=m-1;
}
}
return ans;
}
int main()
{
int cas,c,i;
ll ans;
scanf("%d",&cas);
for(c=1;c<=cas;c++)
{
scanf("%d",&n);
build(1,n,1);
ans=0;
for(i=1;i<=n;i++)
{
int l=find_left(i,a[i]);
int r=find_right(i,a[i]);
//cout<<l<<" "<<r<<endl;
ans=max(ans,a[i]*(r-l+1));
}
printf("Case %d: %lld\n",c,ans);
}
return 0;
}