[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
*/
原文地址:https://www.cnblogs.com/orzzz/p/8038671.html