Description
JOI村有一片荒地,上面竖着N个稻草人,村民们每年多次在稻草人们的周围举行祭典。
有一次,JOI村的村长听到了稻草人们的启示,计划在荒地中开垦一片田地。和启示中的一样,田地需要满足以下条件:
田地的形状是边平行于坐标轴的长方形;
左下角和右上角各有一个稻草人;
田地的内部(不包括边界)没有稻草人。
给出每个稻草人的坐标,请你求出有多少遵从启示的田地的个数
题解
分治。由于是两维的,可以使其中一维有序来降低思考难度。
先按
x
从大到小排序,考虑将元素分成左右两半,考虑如何合并这两半的答案,考虑将两个区间分别按照
时间复杂度:
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxn 200006
#define LL long long
using namespace std;
inline char nc(){
static char buf[100000],*i=buf,*j=buf;
return i==j&&(j=(i=buf)+fread(buf,1,100000,stdin),i==j)?EOF:*i++;
}
inline int _read(){
char ch=nc();int sum=0;
while(!(ch>='0'&&ch<='9'))ch=nc();
while(ch>='0'&&ch<='9')sum=sum*10+ch-48,ch=nc();
return sum;
}
struct data{
int x,y;
bool operator <(const data&b)const{return x<b.x;}
}a[maxn],stack[2][maxn];
int n,top[2];
LL ans;
int find(int x){
int l=1,r=top[1];
while(l<=r){
int mid=(l+r)>>1;
if(stack[1][mid].y>x)l=mid+1;
else r=mid-1;
}
return l;
}
bool cmp(data x,data y){return x.y>y.y;}
void work(int l,int r){
if(l>=r)return;
int mid=(l+r)>>1;
work(l,mid);work(mid+1,r);
top[0]=top[1]=0;int j=mid+1;
for(int i=l;i<=mid;i++){
while(j<=r&&a[j].y>a[i].y){
while(top[1]&&stack[1][top[1]].x>a[j].x)top[1]--;
stack[1][++top[1]]=a[j++];
}
while(top[0]&&stack[0][top[0]].x<a[i].x)top[0]--;
stack[0][++top[0]]=a[i];
if(top[0]>1)ans+=top[1]-find(stack[0][top[0]-1].y)+1;
else ans+=top[1];
}
sort(a+l,a+1+r,cmp);
}
int main(){
freopen("strawman.in","r",stdin);
freopen("strawman.out","w",stdout);
n=_read();
for(int i=1;i<=n;i++)a[i].x=_read(),a[i].y=_read();
sort(a+1,a+1+n);
work(1,n);
printf("%lld\n",ans);
return 0;
}