这个矩形有三个限制,分别是右上角点的横纵坐标分别大于左下角废话,并且中间区域没有点.那么可以先按横坐标排序,然后枚举左边的点和右边的点匹配.为了保证复杂度,这里每次把点集一分为二,先递归处理两边,然后处理两端点分别在左右两边的情况
这里把两边的点分别按纵坐标排序,然后枚举右边的点,每次把左边纵坐标小于右端点的点加进来.然后考虑中间区域没有点的限制,如果左边某个点在某个时刻右上方有点,那么这个点就不能作为端点.左侧可以维护一个从左往右纵坐标单调递减的单调栈.然后考虑右侧其他点对当前右端点的影响,如果有个点在右端点左下方,那么比那个点纵坐标小的左边的点就不能作为左端点.所以如果右边维护一个从左往右纵坐标单调递增的单调栈,那么就可以二分出那个左下的点,推出左端点的纵坐标最小是多少.再在左边单调栈二分出纵坐标最小的满足条件的左端点的位置,那么这个位置到栈顶之间的点都可以作为左端点
#include<bits/stdc++.h> #define LL long long #define uLL unsigned long long #define db double using namespace std; const int N=2e5+10; int rd() { int x=0,w=1;char ch=0; while(ch<'0'||ch>'9'){if(ch=='-') w=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();} return x*w; } struct node { int x,y; }a[N]; bool cmp1(node aa,node bb){return aa.x<bb.x;} bool cmp2(node aa,node bb){return aa.y<bb.y;} int n,st[N]; LL ans; void cdq(int l,int r) { if(l==r) return; int mid=(l+r)>>1; cdq(l,mid),cdq(mid+1,r); int tl=l-1,tr=mid; sort(a+l,a+mid+1,cmp2); sort(a+mid+1,a+r+1,cmp2); for(int i=mid+1,j=l;i<=r;++i) { while(j<=mid&&a[j].y<a[i].y) { while(tl>=l&&a[st[tl]].x<a[j].x) --tl; st[++tl]=j; ++j; } int ll=mid+1,rr=tr,z=0; while(ll<=rr) { int md=(ll+rr)>>1; if(a[st[md]].x<a[i].x) z=st[md],ll=md+1; else rr=md-1; } int ql=l-1; ll=l,rr=tl; while(ll<=rr) { int md=(ll+rr)>>1; if(a[st[md]].y<a[z].y) ql=md,ll=md+1; else rr=md-1; } ans+=max(tl-ql,0); while(tr>mid&&a[st[tr]].x>a[i].x) --tr; st[++tr]=i; } } int main() { n=rd(); for(int i=1;i<=n;++i) a[i].x=rd(),a[i].y=rd(); sort(a+1,a+n+1,cmp1); cdq(1,n); printf("%lld\n",ans); return 0; }
来源:博客园
作者:
链接:https://www.cnblogs.com/smyjr/p/11504666.html