A 国和 B 国是两个超级大国,长期处于冷战状态;
A 国在 B 国中设有 N 个情报站,编号为 1,2,3, …… ,N ,每个情报站有一个坐标 (Xi,Yi) 。但是, A 国的工作人员发现,每个情报站里都被埋上了炸弹!
这些炸弹非常特殊 , 只要同时拆除其中的三个炸弹 , 所有炸弹就都不会爆炸了。
由于各个情报站联络需要代价 , 拆除炸弹需要花费的总代价为这些炸弹两两之间的曼哈顿距离和。
现在 A 国的指挥部门找到了你 , 希望知道可能需要的最大代价和最小代价 。
输入的第一行包含一个整数 N 。接下来 N 行,第 i+1 行两个整数 Xi,Yi ,表示第 i 个情报站的坐标。
输出两行 , 每行包含一个整数 , 第一行表示可能的最大代价 , 第二行表示可能的最小代价。
4
1 1
1 2
2 1
2 3
6
4
对于 30% 的数据, N<=500
对于另外 10% 的数据,每个点出现至少两遍
对于 50% 的数据, N<=1000
对于 60% 的数据, N<=8000
对于 70% 的数据, N<=15000
对于 80% 的数据, N<=50000
对于 100% 的数据, N<=100000 , 0<=Xi,Yi<=10^8
对于两个点 (X0,Y0),(X1,Y1) ,
它们之间的曼哈顿距离为 abs(X0-X1)+abs(Y0-Y1) 。
这道题比较奇妙。
一开始我还以为是什么计算几何神仙题。
结果推一推发现不是。
无脑选手++
最后交了个30分暴力滚粗。
话说这道题数据有点水,可以利用 n 2 n^2 n2卡到90分。
然后利用分段打表两者相结合就过了。
无话可说
100%
我们首先考虑最大值怎么求:
我们发现,一个点对答案做出贡当且仅当其作为Xmin,Xmax,Ymin,Ymax出现才行。
然后贪心做即可。
然后就是最小值怎么求:
我们首先把整个图形旋转90旋转4次,每次就会出现以下两种情况可能对答案有贡献:
对于第一种,我们直接枚举中间的点,然后找出其右上方向离它最近的点,和左下方向离它最近的点。
更新答案即可。
但是一定要注意到重复出现的点。
对于第二种,做法就比较神奇了。
我们看到上图,可以发现,最左下的点提供Xmin,Ymin
最上面的点提供Ymax,最右边的点提供Xmax。
那么我们只需要快速求出后面两个即可。
考虑扫描线,首先当然是离散化y轴啦~
我们考虑从右往左边扫。
在这个y轴建立一个线段树,线段树上每个点记录的是:
x:当前行到扫到的列最近的点的x坐标。
y:在当前行上距离当前行最近的点的y坐标。
ans:当前点作为最右边的点的答案。
那么每次扫到一个点(xi,yi),我们就在线段树上求出它上面的点中答案最小的点。
然后更新。
首先,把当前点所在的行的x更新成xi
然后把当前点下面的行的y都打上lazy标记。
每次下传标记时我们就判断lazy标记是否能更新y值(lazy
小细节真™多。
#include
#include
#include
using namespace std;
struct node
{
long long xmin,ymin,ans;
};
int n;
long long maxans,minans,ans,pp;
long long x[100010],y[100010],ny[100010],id[100010];
long long lazy[400010],t[400010],op[100010][5],gb[400010],xx[100010],yy[100010];
node tree[400010],gbt[400010];
int abs(int x)
{
if (x<0) return -x;
else return x;
}
void qsort(int l,int r)
{
int i=l;int j=r;
int m=xx[(i+j)/2];
int m1=yy[(i+j)/2];
int m2=id[(i+j)/2];
while (i<=j)
{
while ((xx[i]>m)||(xx[i]==m && yy[i]>m1)||(xx[i]==m && yy[i]==m1 && ((pp==0 && id[i]>m2)||(pp==1 && id[i]<m2)))) i++;
while ((xx[j]<m)||(xx[j]==m && yy[j]<m1)||(xx[j]==m && yy[j]==m1 && ((pp==0 && id[j]<m2)||(pp==1 && id[j]>m2)))) j--;
if (i<=j)
{
swap(xx[i],xx[j]);
swap(yy[i],yy[j]);
swap(ny[i],ny[j]);
swap(id[i],id[j]);
i++;j--;
}
}
if (l<j) qsort(l,j);
if (r>i) qsort(i,r);
}
void qsorty(int l,int r)
{
int i=l;int j=r;
int m=yy[(i+j)/2];
while (i<=j)
{
while (yy[i]<m) i++;
while (yy[j]>m) j--;
if (i<=j)
{
swap(yy[i],yy[j]);
swap(xx[i],xx[j]);
swap(id[i],id[j]);
i++;j--;
}
}
if (l<j) qsorty(l,j);
if (r>i) qsorty(i,r);
}
void lazy_down(int x)
{
tree[x*2].ymin=min(tree[x*2].ymin,lazy[x]);
tree[x*2+1].ymin=min(tree[x*2+1].ymin,lazy[x]);
lazy[x*2]=min(lazy[x*2],lazy[x]);
lazy[x*2+1]=min(lazy[x*2+1],lazy[x]);
tree[x*2].ans=min(tree[x*2].ans,tree[x*2].xmin+lazy[x]);
tree[x*2+1].ans=min(tree[x*2+1].ans,tree[x*2+1].xmin+lazy[x]);
lazy[x]=1000000000;
}
void queryall(int x,int l,int r,int st,int en)
{
if (l==st && r==en)
{
ans=min(ans,tree[x].ans);
}
else
{
int mid=(l+r)/2;
lazy_down(x);
if (en<=mid) queryall(2*x,l,mid,st,en);
else if (st>mid) queryall(2*x+1,mid+1,r,st,en);
else
{
queryall(2*x,l,mid,st,mid);
queryall(2*x+1,mid+1,r,mid+1,en);
}
}
}
void find(int x,int l,int r,int st,int en)
{
if (l==st && r==en)
{
ans=min(ans,t[x]);
}
else
{
int mid=(l+r)/2;
if (en<=mid) find(2*x,l,mid,st,en);
else if (st>mid) find(2*x+1,mid+1,r,st,en);
else
{
find(2*x,l,mid,st,mid);
find(2*x+1,mid+1,r,mid+1,en);
}
}
}
void change(int x,int l,int r,int st,int en)
{
if (l==r)
{
t[x]=en;
}
else
{
int mid=(l+r)/2;
if (st<=mid) change(2*x,l,mid,st,en);
else if (st>mid) change(2*x+1,mid+1,r,st,en);
t[x]=min(t[2*x],t[2*x+1]);
}
}
void modifyx(int x,int l,int r,int st,int en)
{
if (l==r)
{
tree[x].xmin=en;
}
else
{
int mid=(l+r)/2;
lazy_down(x);
if (st<=mid) modifyx(2*x,l,mid,st,en);
else if (st>mid) modifyx(2*x+1,mid+1,r,st,en);
tree[x].xmin=min(tree[2*x].xmin,tree[2*x+1].xmin);
}
}
void modifyy(int x,int l,int r,int st,int en,long long op)
{
if (l==st && r==en)
{
if (tree[x].ymin>op)
{
tree[x].ymin=op;
}
lazy[x]=min(lazy[x],op);
tree[x].ans=min(tree[x].ans,tree[x].xmin+op);
}
else
{
int mid=(l+r)/2;
lazy_down(x);
if (en<=mid) modifyy(2*x,l,mid,st,en,op);
else if (st>mid) modifyy(2*x+1,mid+1,r,st,en,op);
else
{
modifyy(2*x,l,mid,st,mid,op);
modifyy(2*x+1,mid+1,r,mid+1,en,op);
}
tree[x].ymin=min(tree[2*x].ymin,tree[2*x+1].ymin);
tree[x].ans=min(tree[2*x].ans,tree[2*x+1].ans);
}
}
void find_min(int now)
{
for (int i=1;i<=n;i++)
{
id[i]=i;
}
qsorty(1,n);
int j=1;
ny[1]=1;
for (int i=2;i<=n;i++)
{
if (yy[i]!=yy[i-1])
{
j++;
}
ny[i]=j;
}
int zd=j;
qsort(1,n);
memcpy(tree,gbt,sizeof(gbt));
memcpy(lazy,gb,sizeof(gb));
memcpy(t,gb,sizeof(gb));
for (int i=1;i<=n;i++)
{
ans=1000000000;
find(1,1,zd,ny[i],zd);
op[id[i]][now]=min(op[id[i]][now],ans-xx[i]-yy[i]);
change(1,1,zd,ny[i],xx[i]+yy[i]);
ans=1000000000;
if (i>=3)
if (ny[i]<zd)
queryall(1,1,zd,ny[i]+1,zd);
minans=min(minans,ans-xx[i]-yy[i]);
modifyx(1,1,zd,ny[i],xx[i]);
if (ny[i]>1)
modifyy(1,1,zd,1,ny[i]-1,yy[i]);
}
}
void find_max()
{
long long xmin=1000000000;
long long ymin=1000000000;
long long xmax=-1000000000;
long long ymax=-1000000000;
for (int i=1;i<=n;i++)
{
xmin=min(xmin,xx[i]);
xmax=max(xmax,xx[i]);
ymin=min(ymin,yy[i]);
ymax=max(ymax,yy[i]);
}
for (int i=1;i<=n;i++)
{
maxans=max(maxans,2*(max(xx[i]-xmin,xmax-xx[i])+max(yy[i]-ymin,ymax-yy[i])));
}
}
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;i++)
{
scanf("%d%d",&x[i],&y[i]);
}
maxans=-1000000000;
minans=1000000000;
for (int i=0;i<400000;i++) gb[i]=1000000000;
for (int i=0;i<400000;i++)
{
gbt[i].ans=1000000000;
gbt[i].xmin=1000000000;
gbt[i].ymin=1000000000;
}
memset(op,127,sizeof(op));
memcpy(xx,x,sizeof(x));
memcpy(yy,y,sizeof(y));
find_max();
for (int i=1;i<=4;i++)
{
memcpy(xx,x,sizeof(x));
memcpy(yy,y,sizeof(y));
if (i==1) find_min(i);
else if (i==2)
{
for (int j=1;j<=n;j++)
{
swap(xx[j],yy[j]);
yy[j]+=100000000;
xx[j]=100000000-xx[j];
}
find_min(i);
}
else
if (i==3)
{
pp++;
for (int j=1;j<=n;j++)
{
xx[j]=6-xx[j];
yy[j]=6-yy[j];
}
find_min(i);
}
else
{
for (int j=1;j<=n;j++)
{
swap(xx[j],yy[j]);
yy[j]=100000000-yy[j];
xx[j]+=100000000;
}
find_min(i);
}
}
for (int i=1;i<=n;i++)
{
minans=min(minans,op[i][1]+op[i][3]);
minans=min(minans,op[i][2]+op[i][4]);
}
printf("%d\n",maxans);
printf("%d\n",minans*2);
}