Description
JOI村有一片荒地,上面竖着个稻草人,村民们每年多次在稻草人们的周围举行祭典。
有一次,JOI村的村长听到了稻草人们的启示,计划在荒地中开垦一片田地。和启示中的一样,田地需要满足以下条件:
田地的形状是边平行于坐标轴的长方形;
左下角和右上角各有一个稻草人;
田地的内部(不包括边界)没有稻草人。
给出每个稻草人的坐标,请你求出有多少遵从启示的田地的个数
Input
第一行一个正整数,代表稻草人的个数
接下来行,第行包含个由空格分隔的整数和,表示第个稻草人的坐标
Output
输出一行一个正整数,代表遵从启示的田地的个数
Sample Input
4
0 0
2 2
3 4
4 3
Sample Output
3
HINT
所有满足要求的田地由下图所示:
互不相同。
互不相同。
Source
JOI 2013~2014 春季training合宿 竞技3 By PoPoQQQ
思路
cdq分治。
首先按排序;
对于两个都在中心一侧的点,递归处理;
然后就只要讨论分居中心左右的点了。
对左右按排序;
左边维护一个单调下降的栈,右边维护一个单调上升的栈,以右边为“自变量”,每次右边加一,往左边一直加,直到左边的下一个的坐标大于右边位置;
现在右边单调上升的栈的栈顶的元素所能构成的矩形个数,就是左边的栈中坐标右侧栈顶与栈的自顶向下第二个元素之间的点之间的元素个数。
代码
#include <cstdio>
#include <algorithm>
#include <iostream>
const int maxn=200000;
template<typename t>
struct stack
{
t c[maxn+10];
int head;
inline int push(t x)
{
++head;
c[head]=x;
return 0;
}
inline int pop()
{
--head;
return 0;
}
inline t top()
{
return c[head];
}
inline int size()
{
return head;
}
inline int clear()
{
head=0;
return 0;
}
};
struct point
{
int x,y;
inline int make_point(int x_,int y_)
{
x=x_;
y=y_;
return 0;
}
};
point d[maxn+10];
stack<point> smaller,bigger;
long long ans;
int n;
bool cmpx(const point &a,const point &b)
{
return a.x<b.x;
}
bool cmpy(const point &a,const point &b)
{
return a.y<b.y;
}
int solve(int l,int r,int pl,int pr)
{
if((l==r)||(pl>pr))
{
return 0;
}
std::sort(d+pl,d+pr+1,cmpx);
int mid=(l+r)>>1,pmid=0;
if(d[pl].x>mid)
{
solve(mid+1,r,pl,pr);
return 0;
}
if(d[pr].x<=mid)
{
solve(l,mid,pl,pr);
return 0;
}
for(register int i=pl+1; i<=pr; ++i)
{
if(d[i].x>mid)
{
solve(l,mid,pl,i-1);
solve(mid+1,r,i,pr);
pmid=i-1;
break;
}
}
std::sort(d+pl,d+pmid+1,cmpy);
std::sort(d+pmid+1,d+pr+1,cmpy);
int i=pmid+1,j=pl;
smaller.clear();
bigger.clear();
while((i<=pr)||(!bigger.size()))
{
while((bigger.size())&&(bigger.top().x>d[i].x))
{
bigger.pop();
}
point prep=bigger.top();
bigger.push(d[i]);
while((j<=pmid)&&(d[j].y<d[i].y))
{
while((smaller.size())&&(smaller.top().x<d[j].x))
{
smaller.pop();
}
smaller.push(d[j]);
++j;
}
int left=1,right=smaller.size(),res=0;
while(left<=right)
{
int m=(left+right)>>1;
if(smaller.c[m].y>=prep.y)
{
right=m-1;
}
else
{
left=m+1;
res=m;
}
}
ans+=(bigger.size()==1)?smaller.size():(smaller.size()-res);
++i;
}
return 0;
}
int main()
{
scanf("%d",&n);
for(register int i=1; i<=n; ++i)
{
scanf("%d%d",&d[i].x,&d[i].y);
}
solve(0,1000000000,1,n);
printf("%I64d\n",ans);
return 0;
}