[Bzoj4237]稻草人

题意:给你一些点,问由这些点构成右上角和左下角的长方形个数,并且矩形内部不能有其他点
按照 y y 坐标来分治,分成上下两块
对于某一段我们按照x排序,考虑下面的点与上面的点配成的矩形的个数
考虑以当前点 i i 为右上角,计算下面有多少点j能与 i i 配成矩形
首先要满足这样几种情况
①:xj<xi
②: xj>x x j > x 上面的离 i i 最近且y<yi的点
给张图就是这样的
这里写图片描述
图中 (x1,y1) ( x 1 , y 1 ) 就是不合法的点
对于我们来说 (x2,y2) ( x 2 , y 2 ) 这样的点已经没有用了
但是 (x3,y3) ( x 3 , y 3 ) 这样的点还是有用的
不难想到我们要在上面维护一个单调上升的栈
如果下面的点 a,b a , b 满足 b b a的右上方,那么 a a 就没用了
所以我们也要在下面维护一个单调下降的栈
对于每一个上面的点,因为x是单调的
所以我们可以在下面的栈里二分找到第一个不满足条件②的点

#include<bits/stdc++.h>
#define fp(i,a,b) for(register int i=a,I=b+1;i<I;++i)
#define fd(i,a,b) for(register int i=a,I=b-1;i>I;--i)
#define go(u) for(register int i=fi[u],v=e[i].to;i;v=e[i=e[i].nx].to)
#define file(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
char ss[1<<17],*A=ss,*B=ss;
inline char gc(){return A==B&&(B=(A=ss)+fread(ss,1,1<<17,stdin),A==B)?-1:*A++;}
template<class T>inline void sd(T&x){
    char c;T y=1;while(c=gc(),(c<48||57<c)&&c!=-1)if(c==45)y=-1;x=c-48;
    while(c=gc(),47<c&&c<58)x=x*10+c-48;x*=y;
}
char sr[1<<21],z[20];int C=-1,Z;
inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;}
template<class T>inline void we(T x){
    if(C>1<<20)Ot();if(x<0)sr[++C]=45,x=-x;
    while(z[++Z]=x%10+48,x/=10);
    while(sr[++C]=z[Z],--Z);sr[++C]='\n';
}
const int N=2e5+5;
typedef int arr[N];
struct da{int x,y;}a[N],b[N];
int n;arr s1,s2;long long ans;
inline int bf(int x,int L,int R){
    int mid=(L+R)>>1;
    for(;L+1<R;mid=(L+R)>>1)
        if(a[s2[mid]].x<x)L=mid;else R=mid;
    return L;
}
void cdq(int L,int R){
    if(L==R)return;int mid=(L+R)>>1;
    cdq(L,mid),cdq(mid+1,R);
    int t1=0,t2=0,i=L,j=mid+1;
    for(;j<=R;++j){
        while(t1&&a[j].y<a[s1[t1]].y)--t1;
        s1[++t1]=j;
        for(;i<=mid&&a[i].x<a[j].x;++i){
            while(t2&&a[i].y>a[s2[t2]].y)--t2;
            s2[++t2]=i;
        }
        ans+=t2-bf(a[s1[t1-1]].x,0,t2+1);
    }i=L,j=mid+1;
    fp(k,L,R)b[k]=((i<=mid&&a[i].x<a[j].x)||j>R)?a[i++]:a[j++];
    fp(k,L,R)a[k]=b[k];
}
inline bool cpy(const da&a,const da&b){return a.y<b.y;}
int main(){
    #ifndef ONLINE_JUDGE
        file("s");
    #endif
    sd(n);
    fp(i,1,n)sd(a[i].x),sd(a[i].y);
    sort(a+1,a+n+1,cpy);
    cdq(1,n);
    we(ans);
return Ot(),0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值