• [bzoj4237]稻草人


    1A了好高兴。。cdq分治的思想。感觉难点在单调栈。


    Description 

    JOI村有一片荒地,上面竖着$N$个稻草人,村民们每年多次在稻草人们的周围举行祭典。
    有一次,JOI村的村长听到了稻草人们的启示,计划在荒地中开垦一片田地。和启示中的一样,田地需要满足以下条件:
    田地的形状是边平行于坐标轴的长方形;
    左下角和右上角各有一个稻草人;
    田地的内部(不包括边界)没有稻草人。

    给出每个稻草人的坐标,请你求出有多少遵从启示的田地的个数

    Input

    第一行一个正整数N,代表稻草人的个数
    接下来N行,第i行($1<=i<=N$)包含2个由空格分隔的整数$Xi$和$Yi$,表示第$i$个稻草人的坐标

    Output

    输出一行一个正整数,代表遵从启示的田地的个数

    Sample Input

    4
    0 0
    2 2
    3 4
    4 3

    Sample Output

    3

    HINT

    所有满足要求的田地由下图所示:

     

    $1<=N<=2*10^5$

    $0<=Xi<=10^9(1<=i<=N)$

    $0<=Yi<=10^9(1<=i<=N)$

    $Xi(1<=i<=N)$互不相同。

    $Yi(1<=i<=N)$互不相同。


    %出题人!!

    首先分治处理:在区间$[l,r]$内,计算左下角的$x$在$[l,mid]$,右上角的$x$在$[mid+1,r]$的数量,递归下去。不重不漏。

    那么就先将所有点按$x$排序,没啥说的。

    那么在区间$[l,r]$内,分为左右两边$[l,mid],[mid+1,r]$:

    左右各维护一个单调栈,左边称为$s1$,是单调递减,右边叫$s2$,是单调递增的。为啥呢?

    考虑枚举右边的点。每次按$y$从小到大将右边的点加入$s2$。

    右边的一个点$p$与左边的一个点$q$不能遵从启示(误)的情况有三种:

    1.$p_y>q_y$  2.$p,q$之间有左边的点  3.$p,q$之间有右边的点

    于是我们知道对于左边的点,它左下方的点不会造成影响。类似的,对于右边的点,其右下方也不会造成影响。

    所以按y从小到大将右边点顺序加入$s2$,同时将栈内比他的x大的弹出$s2$。因为这些点造成情况3时,当前点也可以造成。

    然后将所有y小于当前点的左侧点加入$s1$。每加入一个点,将栈内比他的$x$小的弹出$s1$。因为这些点不可能再与右侧点形成矩形了——他们会被加入的这个点阻碍形成情况2。

    于是每次查找比加入$s2$前,$s2$的栈顶的$y$大的,$s1$中的点有多少个。二分就行了。否则会出现情况3啊。

    说的很麻烦,看代码吧qwq。跑得巨慢 =_=。下面我造的一组样例可以手玩一下。

    #include<bits/stdc++.h>
    using namespace std;
    const int N=200010;
    inline int read(){
        int r=0,c=getchar();
        while(!isdigit(c))c=getchar();
        while(isdigit(c))
        r=r*10+c-'0',c=getchar();
        return r;
    }
    struct qwq{
        int x,y;
    }a[N];
    bool cmpx(qwq p,qwq q){
        return p.x<q.x;
    }
    bool cmpy(qwq p,qwq q){
        return p.y<q.y;
    }
    struct Stack{
        int t;qwq s[N];
        Stack(){
            t=0;memset(s,0,sizeof s);
        }
        int size(){return t;}
        bool empty(){return !t;}
        void pop(){t--;}
        void push(qwq x){s[++t]=x;}
        qwq top(){return s[t];}
        int find(int x){
            int l=0,r=t;
            while(r-l>1){
                int mid=l+r>>1;
                if(s[mid].y<x)l=mid;
                else r=mid;
            }
            if(s[r].y<x)return r;
            else return l;
        }
        void clear(){while(!empty())pop();}
    }sl,sr;
    long long ans;
    void cdq(int l,int r){
        if(l==r)return;
        int mid=l+r>>1;
        sort(a+l,a+mid+1,cmpy);sort(a+mid+1,a+r+1,cmpy);
        sl.clear();sr.clear();
        for(int i=mid+1,j=l;i<=r;i++){
            while(!sr.empty()&&sr.top().x>a[i].x)sr.pop();
            while(j<=mid&&a[j].y<a[i].y){
                while(!sl.empty()&&sl.top().x<a[j].x)sl.pop();
                sl.push(a[j]);j++;
            }
            int t=sl.size()-sl.find(sr.top().y);
            ans+=1ll*t;
            sr.push(a[i]);
        }
        sort(a+l,a+r+1,cmpx);
        cdq(l,mid);cdq(mid+1,r);
    }
    int main(){
        int n=read();
        for(int i=1;i<=n;i++)
        a[i].x=read(),a[i].y=read();
        sort(a+1,a+n+1,cmpx);
        cdq(1,n);
        printf("%lld
    ",ans);
    }
    /*
    7
    3 1
    7 2
    4 3
    1 4
    6 5
    2 6
    5 7
    */
  • 相关阅读:
    5月27 开通博客啦
    源码编译安装mysql-boost-5.7.16.tar.gz报错分析处理
    MHA实践操作
    (转)MySQL高可用方案MHA的部署和原理
    Mysql利用binlog日志恢复数据操作(转)
    生产环境mysql数据库主从恢复从数据库 -- flush tables with read lock;
    带着问题学习openstack
    openstack的网络模式(转)
    openstack 镜像初始化root登录密码
    openstack placement 组件作用理解
  • 原文地址:https://www.cnblogs.com/orzzz/p/8038671.html
Copyright © 2020-2023  润新知