这个题其实应该算4个二维偏序,因为枚举每个点可以根据公式分成4个象限,4种计算方式,所以就考虑怎么求x和y的大小关系集合
首先,按x排序再枚举,可以保证后面的x大于前面的x,就相当于分成了两部分,剩下的就是区分y的大小关系,相当于是在两个x的区间里找一个值左侧和右侧的信息,
如果分成4个信息,就相当于维护四个值:x+y,x-y,y-x,-x-y的最大最小值, 对于查询,就是标准的线段树问题,
所以动态维护线段树,在四个面里取最值就可以了
码:
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
#define zuo o<<1,l,mid
#define you o<<1|1,mid+1,r
#define N 100005
int xyd[N<<2],xyx[N<<2],fxyd[N<<2],fxyx[N<<2],fxfyd[N<<2],fxfyx[N<<2],xfyx[N<<2],xfyd[N<<2],a,b,maxx,minn,ans=999999999,op,i,n,dui[N];
struct la
{
int x,y,id;
}d[N],D[N];
bool cmp(la a,la b)
{
if(a.x==b.x)
return a.y<b.y;
else return a.x<b.x;
}
bool cmp2(la a,la b)
{
if(a.y==b.y)
return a.x<b.x;
else return a.y<b.y;
}
void up(int o)
{
int ll=o<<1,rr=o<<1|1;
xyd[o]=max(xyd[ll],xyd[rr]);
fxyd[o]=max(fxyd[ll],fxyd[rr]);
xfyd[o]=max(xfyd[ll],xfyd[rr]);
fxfyd[o]=max(fxfyd[ll],fxfyd[rr]);
xyx[o]=min(xyx[ll],xyx[rr]);
fxyx[o]=min(fxyx[ll],fxyx[rr]);
xfyx[o]=min(xfyx[ll],xfyx[rr]);
fxfyx[o]=min(fxfyx[ll],fxfyx[rr]);
}
void jian(int o,int l,int r)
{
if(l==r)
{
xfyx[o]=fxfyx[o]=fxyx[o]=999999999;
xfyd[o]=fxfyd[o]=fxyd[o]=-999999999;
xyx[o]=xyd[o]=D[l].x+D[l].y;
fxyx[o]=fxyd[o]=D[l].y-D[l].x;
return ;
}
int mid=(l+r)>>1;
jian(zuo);
jian(you);
up(o);
}
void gai(int o,int l,int r)
{
if(a<=l&&r<=b)
{
if(op==0)
{
xyx[o]=fxyx[o]=999999999;
xyd[o]=fxyd[o]=-999999999;
}
if(op==1)
{
xfyx[o]=xfyd[o]=D[l].x-D[l].y;
fxfyx[o]=fxfyd[o]=-D[l].y-D[l].x;
}
if(op==2)
{
minn=min(minn,d[i].x-d[i].y-xfyd[o]);
maxx=max(maxx,d[i].x-d[i].y-xfyx[o]);
}
if(op==3)
{
minn=min(minn,d[i].x+d[i].y+fxfyx[o]);
maxx=max(maxx,d[i].x+d[i].y+fxfyd[o]);
}
if(op==4)
{
minn=min(minn,xyx[o]-(d[i].x+d[i].y));
maxx=max(maxx,xyd[o]-(d[i].x+d[i].y));
}
if(op==5)
{
minn=min(minn,d[i].y-d[i].x-fxyd[o]);
maxx=max(maxx,d[i].y-d[i].x-fxyx[o]);
}
return;
}
int mid=(l+r)>>1;
if(a<=mid)gai(zuo);
if(b>mid)gai(you);
up(o);
}
int main()
{
scanf("%d",&n);
for(i=1;i<=n;i++)
{
scanf("%d%d",&d[i].x,&d[i].y);
d[i].id=i;
D[i]=d[i];
}
sort(d+1,d+1+n,cmp);
sort(D+1,D+1+n,cmp2);
for(i=1;i<=n;i++)
{
dui[D[i].id]=i;
}
jian(1,1,n);
for(i=1;i<=n;i++)
{
op=0;//清除右面的
a=b=dui[d[i].id];
gai(1,1,n);
minn=999999999;
maxx=-999999999;
//计算
op=2;a=dui[d[i].id]+1;b=n; //找左上角
if(a<=b)gai(1,1,n);
op=3;a=1;b=dui[d[i].id]-1; //找左下角
if(a<=b)gai(1,1,n);
op=4;a=dui[d[i].id]+1;b=n; //找右上角
if(a<=b)gai(1,1,n);
op=5;a=1;b=dui[d[i].id]-1; //找右下角
if(a<=b)gai(1,1,n);
ans=min(maxx-minn,ans);
op=1;//加入左面的
a=b=dui[d[i].id];
gai(1,1,n);
}
printf("%d",ans);
}