• [Code+#3]寻找车位


    题目描述

    access_globe 有一个巨大的停车场,这个停车场有 n 行,每行有 m 个车位。为了美观,access_globe 在建立这个停车场时,规定这个停车场必须是长条形的,即 nm。每个车位都是一个正方形的区域。

    最近,access_globe 正在为抽不到 Missing Poster 而苦恼,因此他请你帮他维护这个停车场。你需要支持两个个事件:

    • 一辆车停到某一个车位中,或一辆车从某个车位开走
    • 查询一个矩形区域内最大的只包含空车位的正方形区域

    如果你能帮 access_globe 高效地解决这个问题,access_globe 一定会好好奖励你的

    题解

    因为n>m所以我们发现m其实是不大的,所以我们可以稍微放宽复杂度,qmlogn就可以了。

    我们可以用线段树去维护每一行的值,一个upmax,一个downmx,一个mx。

    upmx就是从上面往下数最长一段连续的1也就是黄色部分,downmx为红色部分。

    mx表示这个子矩形中最大的全1矩阵。

    然后我们可以利用子树合并来维护这三个数组。

    维护方法:用两个单调队列储存边界信息。

    然后维护一个指针p来维护最大子矩形的上边界。

    这样修改就好说了。

    那么对于一个询问,它的边界不是1~m怎么办?

    我们还可以O(m)的做一遍,对于每个节点储存的最大子矩形,我们卡一下边界就好了。

    代码

    #include<iostream>
    #include<cstdio>
    #define N 4000009
    using namespace std;
    int n,m,q1[N],q2[N],ans,now;
    inline int rd(){
        int x=0;char c=getchar();bool f=0;
        while(!isdigit(c)){if(c=='-')f=1;c=getchar();}
        while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
        return f?-x:x;
    }
    struct node{
        int a[N<<2];
        int* operator[](int x){return a+x*m;}
    }upmx,downmx,sum,a;
    void merge(int cnt,int l,int r,int len1,int len2){
         int h1=1,h2=1,t1=0,t2=0,p=l;
         for(int i=l;i<=r;++i){
             while(h1<=t1&&downmx[cnt<<1][i]<downmx[cnt<<1][q1[t1]])t1--;q1[++t1]=i;
             while(h2<=t2&&upmx[cnt<<1|1][i]<upmx[cnt<<1|1][q2[t2]])t2--;q2[++t2]=i;
            while(h1<=t1&&h2<=t2&&i-p+1>downmx[cnt<<1][q1[h1]]+upmx[cnt<<1|1][q2[h2]]){
                p++;
                while(h1<=t1&&q1[h1]<p)h1++;while(h2<=t2&&q2[h2]<p)h2++;
            }
            sum[cnt][i]=max(sum[cnt<<1][i],sum[cnt<<1|1][i]);
            if(h1<=t1&&h2<=t2)sum[cnt][i]=max(sum[cnt][i],i-p+1);
        //    cout<<len1<<" "<<len2<<" "<<sum[cnt][i]<<endl; 
         }
         for(int i=l;i<=r;++i){
             upmx[cnt][i]=upmx[cnt<<1][i]+(upmx[cnt<<1][i]==len1?upmx[cnt<<1|1][i]:0);
             downmx[cnt][i]=downmx[cnt<<1|1][i]+(downmx[cnt<<1|1][i]==len2?downmx[cnt<<1][i]:0);
         }
    }
    void build(int cnt,int l,int r){
        if(l==r){
            for(int i=1;i<=m;++i)
              upmx[cnt][i]=downmx[cnt][i]=sum[cnt][i]=a[l][i];
            return;
        }
        int mid=(l+r)>>1;
        build(cnt<<1,l,mid);build(cnt<<1|1,mid+1,r);
        merge(cnt,1,m,mid-l+1,r-mid);
    }
    void upd(int cnt,int l,int r,int x,int y){
        if(l==r){
            sum[cnt][y]^=1;upmx[cnt][y]=downmx[cnt][y]=sum[cnt][y];
            return;
        }
        int mid=(l+r)>>1;
        if(mid>=x)upd(cnt<<1,l,mid,x,y);
        else upd(cnt<<1|1,mid+1,r,x,y);
        merge(cnt,1,m,mid-l+1,r-mid); 
    }
    void merge2(int cnt,int l,int r,int len){
         int h1=1,h2=1,t1=0,t2=0,p=l;
         for(int i=l;i<=r;++i){
             while(h1<=t1&&downmx[0][i]<=downmx[0][q1[t1]])t1--;q1[++t1]=i;
             while(h2<=t2&&upmx[cnt][i]<=upmx[cnt][q2[t2]])t2--;q2[++t2]=i;
            while(h1<=t1&&h2<=t2&&i-p+1>downmx[0][q1[h1]]+upmx[cnt][q2[h2]]){
                p++;
                while(h1<=t1&&q1[h1]<p)h1++;while(h2<=t2&&q2[h2]<p)h2++;
            }
            ans=max(ans,min(i-l+1,sum[cnt][i]));
            if(h1<=t1&&h2<=t2)ans=max(ans,i-p+1);
         }
         for(int i=l;i<=r;++i){
             upmx[0][i]=upmx[0][i]+(upmx[0][i]==now?upmx[cnt][i]:0);
             downmx[0][i]=downmx[cnt][i]+(downmx[cnt][i]==len?downmx[0][i]:0);
         }
    }
    void query(int cnt,int l,int r,int L,int R,int s,int t){
        if(l>=L&&r<=R){
            merge2(cnt,s,t,r-l+1);
            now+=(r-l+1);
            return;
        }
        int mid=(l+r)>>1;
        if(mid>=L)query(cnt<<1,l,mid,L,R,s,t);
        if(mid<R)query(cnt<<1|1,mid+1,r,L,R,s,t);
    }
    int main(){
        n=rd();m=rd();int q=rd();
        for(int i=1;i<=n;++i)
            for(int j=1;j<=m;++j)a[i][j]=rd();
        build(1,1,n);
        int opt,x,y,l,s,r,t;
        while(q--){
            opt=rd();
            if(!opt){
                x=rd();y=rd();
                upd(1,1,n,x,y);
            }
            else{
                l=rd();s=rd();r=rd();t=rd();
                ans=0;now=0;
                for(int i=s;i<=t;++i)upmx[0][i]=downmx[0][i]=0;
                query(1,1,n,l,r,s,t);
                printf("%d
    ",ans); 
            }
        }
        return 0;
    } 
  • 相关阅读:
    nignx的master进程和worker进程的作用
    JVM运行机制
    ElasticSearch介绍与安装
    Maven打可执行包的pom.xml配置
    pg按日,周,月进行数据统计
    数据库中重复数据查询和删除
    聚类算法的评估应面向具体问题
    将博客搬至CSDN
    Mutual Information
    层次化聚类
  • 原文地址:https://www.cnblogs.com/ZH-comld/p/10399471.html
Copyright © 2020-2023  润新知