4237: 稻草人


Time Limit: 40 Sec   Memory Limit: 256 MB

Submit: 791  

Solved: 353

[Submit][Status][Discuss]


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)互不相同。




Source


JOI 2013~2014 春季training合宿 竞技3 By PoPoQQQ




【分析】

CDQ分治+单调栈+二分



【代码】

//bzoj 4237 稻草人
#include<bits/stdc++.h>
#define ll long long
#define M(a) memset(a,0,sizeof a)
#define fo(i,j,k) for(i=j;i<=k;i++)
using namespace std;
const int mxn=200005;
ll ans;
int n,m,T,top1,top2;
struct node {int x,y;} a[mxn],tmp[mxn],s1[mxn],s2[mxn]; 
inline bool comp(node u,node v)
{
	return u.y<v.y;
}
inline int find(int l,int r,int x)
{
	while(l<r)
	{
		int mid=(l+r>>1)+1;
		if(x>s1[mid].x) l=mid;
		else r=mid-1;
	}
	return l;
}
inline void CDQ(int l,int r)
{
	if(l==r) return;
	int i,j,mid=l+r>>1,l1=l,l2=mid+1;
	CDQ(l,mid),CDQ(mid+1,r);
	top1=top2=0;
	for(l2=mid+1;l2<=r;l2++)
	{
		while(top2 && a[l2].y<s2[top2].y) top2--;
		s2[++top2]=a[l2];
		for(l1;l1<=mid && a[l1].x<a[l2].x;l1++)
		{
			while(top1 && a[l1].y>s1[top1].y) top1--;
			s1[++top1]=a[l1];
		}
		ans+=top1-find(0,top1,s2[top2-1].x);
	}
	l1=l,l2=mid+1;
	fo(i,l,r)
	  tmp[i]=((l1<=mid && a[l1].x<a[l2].x) || l2>r)?a[l1++]:a[l2++];
	fo(i,l,r) a[i]=tmp[i];
}
int main()
{
	int i,j;
	scanf("%d",&n);
	fo(i,1,n)
	  scanf("%d%d",&a[i].x,&a[i].y);
	sort(a+1,a+n+1,comp);
	CDQ(1,n);
	printf("%lld\n",ans);
	return 0;
}