BZOJ 4237: 稻草人

4237: 稻草人

Time Limit: 40 Sec  Memory Limit: 256 MB
Submit: 661  Solved: 286
[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

思(心)考(塞)历程:

晚上看ysq大佬(%%%)秒切NeighThorn做过的题的时候听到玉环在思考这题...然后NeighThorn和YouSiki果断弃掉NT做过的水题来思考YYH大佬的神题...

然后两个人对着屏幕和草稿纸陷入了深思...

一千八百万年之后NT赶脚自己YY出了一个漏洞百出的方法...(真的是漏洞百出...

感觉我们可以统计每个点对答案的贡献,因为这是个二维的东西,所以可能可以通过分治什么的降到一维...

我们把所有的点按照x轴坐标排序,然后对y坐标分治,这样我们统计对于上层的每个节点下层有多少个节点可以和其构成合法答案...

如果下层的点出现了这种情况...显然对于3节点来说1节点是没有用的...

所以我们对于下层节点维护一个y坐标单调递减的栈,对于上层的每个节点在下层的单调栈里二分答案...

然后被YouSiki大佬D得很惨...虽然他也被NT卡掉了(hia~hia~hia~...

然后NT满心欢喜地对YouSiki说:“你去写吧,我懒得写了..."被YouSiki严肃地拒绝了...

对于一切早已习惯并且淡然了的NT回到电脑屏幕前开始发呆,忽然发现这样是错误的,然后错的还很明显...(所以NT和YouSiki的脑子都锈掉了???

于是NT和YouSiki再次经过了和平的争吵之后YouSiki童鞋说出了正解...

我们现在不对上层的每个节点去寻找答案,而是直接计算跨越上下层的合法矩形个数...

我们对于上层节点维护y坐标单调递增的栈,下层节点维护y坐标单调递减的栈...

就是酱紫:

我们枚举上面的点,对于上面的某个点a我们要找到它前面的第一个高度小于它的点来卡住它的下面的点b,就是说下面二分的时候的x坐标是要通过b的x坐标来卡边界的...

一个分治里面有个二分...时间复杂度$O(nlog^{2}n)$...

然后NT表示YouSiki太厉害了...然后大爷就又愉快地开始了每天必做功课:催人...

代码:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
//by NeighThorn
using namespace std;

const int maxn=200000+5;

int n,cnt1,cnt2,top1,top2,mp[2][maxn];

long long ans;

struct M{
	int x,y;
	friend bool operator < (M a,M b){
		return a.x<b.x;
	}
}stk[2][maxn],pos[maxn],q[maxn];

inline void CDQ(int l,int r){
	if(l==r)
		return;
	int mid=(l+r)>>1,b1=l,b2=mid+1;
	for(int i=l;i<=r;i++){
		if(pos[i].y<=mid)
			q[b1++]=pos[i];
		else
			q[b2++]=pos[i];
	}
	memcpy(pos+l,q+l,sizeof(M)*(r-l+1));
	top1=top2=0;
	for(int i=l,j=mid+1;j<=r;j++){
		while(i<=mid&&pos[i].x<pos[j].x){
			while(top1&&stk[0][top1].y<pos[i].y)
				top1--;
			stk[0][++top1]=pos[i];i++;
		}
		while(top2&&stk[1][top2].y>pos[j].y)
			top2--;
		stk[1][++top2]=pos[j];
		ans+=top1-(lower_bound(stk[0]+1,stk[0]+top1+1,stk[1][top2-1])-stk[0])+1;
	}
	CDQ(l,mid),CDQ(mid+1,r);
}

signed main(void){
	scanf("%d",&n);ans=0;
	for(int i=1;i<=n;i++)
		scanf("%d%d",&pos[i].x,&pos[i].y),mp[0][i]=pos[i].x,mp[1][i]=pos[i].y;
	sort(mp[0]+1,mp[0]+n+1);sort(mp[1]+1,mp[1]+n+1);
	cnt1=unique(mp[0]+1,mp[0]+n+1)-mp[0]-1,cnt2=unique(mp[1]+1,mp[1]+n+1)-mp[1]-1;
	for(int i=1;i<=n;i++)
		pos[i].x=lower_bound(mp[0]+1,mp[0]+cnt1+1,pos[i].x)-mp[0],
		pos[i].y=lower_bound(mp[1]+1,mp[1]+cnt2+1,pos[i].y)-mp[1];
	sort(pos+1,pos+n+1);CDQ(1,n);
	printf("%lld\n",ans);
	return 0;
}

  


By NeighThorn

posted @ 2017-02-18 00:12  NeighThorn  阅读(398)  评论(3编辑  收藏  举报