【单调队列】[CQBZOJ2436]Zj 之 XX 洗浴

题目描述
众所周知,这个就不扩展了……
自从这次被抓以后,zj同学很不服气。回家后,zj 就开始了他的计划!(你不让我
洗浴,我就在家洗个痛快!)zj 打算在自家的院子里修一个洗浴池,当然他希望洗
浴池越大越好。但是院子里有 zj喜欢的一些植物,他不想毁掉任一颗植物,所以洗浴池不能将植物的位置占掉。zj的院子和洗浴池都是矩形的,浴池要完全处在院
子里,并且浴池的轮廓要与院子的轮廓平行或重合。每个植物可以看做一个点,浴
池不能覆盖任何一个植物点,但是植物点可以在浴池的边上,请问 zj 的浴池最大
能修多大.
输入
输入文件的第一行包含两个整数l和w,分别表示院子的长和宽。文件的第二行包
含一个整数n,表示植物的数量。以下n行每行包含两个整数x和y,表示一个植物
点的坐标。所有植物点都位于院子内,即:0 ≤ x ≤ l,0 ≤ y ≤ w。
输出
输出文件仅一行,包含一个整数s,表示浴池的最大面积。

样例输入
Copy (如果复制到控制台无换行,可以先粘贴到文本编辑器,再复制)

10 10
4
1 1
9 1
1 9
9 9
样例输出
80
提示
【数据范围】

0 ≤ n ≤ 5000,1 ≤ l ,w ≤ 30000

来源
HZOI

对每一行的点,找出它到该列上方最近的植物点的距离,可以看做矩形的最大宽度,然后向左右延伸,对每一行都求出一个最大的矩形。所有行的最大矩形即为答案。
总的时间复杂度为O(N^N).
本题点的坐标范围太大,需要先进行离散化。
要用单调队列或者堆栈进行优化。

#include<cstdio>
#include<algorithm>
#include<queue>
using namespace std;
#define MAXN 5000
bool mat[MAXN+10][MAXN+10];
void Read(int &x){
    char c;
    while(c=getchar(),c!=EOF)
        if(c>='0'&&c<='9'){
            x=c-'0';
            while(c=getchar(),c>='0'&&c<='9')
                x=x*10+c-'0';
            ungetc(c,stdin);
            return;
        }
}
int l,w,n,ans,x[MAXN+10],cntx,cnty,y[MAXN+10],h[MAXN+10],s[MAXN+10],front,rear;
pair<int,int>a[MAXN+10],q[MAXN+10];
void init(){
    Read(l),Read(w),Read(n);
    int i;
    for(i=1;i<=n;i++){
        Read(a[i].first),Read(a[i].second);
        x[i]=a[i].first;
        y[i]=a[i].second;
    }
    x[n+1]=l;
    y[n+1]=w;
    sort(x+1,x+n+2);
    cntx=unique(x,x+n+2)-x-1;
    sort(y+1,y+n+2);
    cnty=unique(y,y+n+2)-y-1;
    for(i=1;i<=n;i++)
        mat[lower_bound(x+1,x+cntx+1,a[i].first)-x][lower_bound(y+1,y+cnty+1,a[i].second)-y]=1;
}
void solve(){
    int i,j;
    for(i=1;i<=cntx;i++){
        front=1,rear=0;
        q[0]=make_pair(0,0);
        for(j=1;j<=cnty;j++){
            h[j]+=x[i]-x[i-1];
            while(front<=rear&&q[rear].first>=h[j])
                rear--;
            s[j]=h[j]*(y[j]-q[rear].second);
            q[++rear]=make_pair(h[j],y[j]);
        }
        front=1,rear=0;
        q[0]=make_pair(0,w);
        for(j=cnty-1;j;j--){
            while(front<=rear&&q[rear].first>h[j])
                rear--;
            s[j]+=h[j]*(q[rear].second-y[j]);
            q[++rear]=make_pair(h[j],y[j]);
            ans=max(ans,s[j]);
            if(mat[i][j])
                h[j]=0;
        }
    }
    for(j=1;j<=cnty;j++)
        ans=max(ans,l*(y[j]-y[j-1]));
}
int main()
{
    init();
    solve();
    printf("%d",ans);
}
posted @ 2015-09-24 13:38  outer_form  阅读(157)  评论(0编辑  收藏  举报