bzoj 4237 稻 草 人

bzoj

这个矩形有三个限制,分别是右上角点的横纵坐标分别大于左下角废话,并且中间区域没有点.那么可以先按横坐标排序,然后枚举左边的点和右边的点匹配.为了保证复杂度,这里每次把点集一分为二,先递归处理两边,然后处理两端点分别在左右两边的情况

这里把两边的点分别按纵坐标排序,然后枚举右边的点,每次把左边纵坐标小于右端点的点加进来.然后考虑中间区域没有点的限制,如果左边某个点在某个时刻右上方有点,那么这个点就不能作为端点.左侧可以维护一个从左往右纵坐标单调递减的单调栈.然后考虑右侧其他点对当前右端点的影响,如果有个点在右端点左下方,那么比那个点纵坐标小的左边的点就不能作为左端点.所以如果右边维护一个从左往右纵坐标单调递增的单调栈,那么就可以二分出那个左下的点,推出左端点的纵坐标最小是多少.再在左边单调栈二分出纵坐标最小的满足条件的左端点的位置,那么这个位置到栈顶之间的点都可以作为左端点

#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
",ans);
	return 0; 
}
原文地址:https://www.cnblogs.com/smyjr/p/11504666.html