教主的花园
题目描述
教主最近总困扰于前来膜拜他的人太多了,所以他给他的花园加上了一道屏障。
可以把教主的花园附近区域抽像成一个正方形网格组成的网络,每个网格都对应了一个坐标(均为整数,有可能为负),若两个网格(x1, y1),(x2, y2)有|x1 - x2| + |y1 - y2| = 1,则说这两个网格是相邻的,否则不是相邻的。
教主在y = 0处整条直线上的网格设置了一道屏障,即所有坐标为(x, 0)的网格。当然,他还要解决他自己与内部人员的进出问题,这样教主设置了N个入口a1, a2, …, aN可供进出,即对于y = 0上的所有网格,只有 (a1, 0),(a2, 0), ……, (aN, 0) 可以通过,之外的所有纵坐标为0的网格均不能通过,而对于(x, y)有y不为0的网格可以认为是随意通过的。
现在教主想知道,给定M个点对(x1, y1),(x2, y2),并且这些点均不在屏障上,询问从一个点走到另一个点最短距离是多少,每次只能从一个格子走到相邻的格子。
输入
输入的第1行为一个正整数N,为屏障上入口的个数。
第2行有N个整数,a1, a2, …, aN,之间用空格隔开,为这N个入口的横坐标。
第3行为一个正整数M,表示了M个询问。
接下来M行,每行4个整数x1, y1, x2, y2,有y1与y2不等于0,表示了一个询问从(x1, y1)到(x2, y2)的最短路。
输出
输出共包含m行,第i行对于第i个询问输出从(x1, y1)到(x2, y2)的最短路距离是多少
样例输入
2
2 -1
2
0 1 0 -1
1 1 2 2
样例输出
4
2
提示
【数据范围及约定】
对于20%的数据,有n,m≤10,ai,xi,yi绝对值不超过100;
对于40%的数据,有n,m≤100,ai,xi,yi绝对值不超过1000;
对于60%的数据,有n,m≤1000,ai,xi,yi绝对值不超过100000;
对于100%的数据,有n,m≤100000,ai,xi,yi绝对值不超过100000000。
这道题也分两种情况:y1,y2同号,直接横纵坐标绝对值差为解。
第二种不在同侧,那么判断一下两者之间的X轴上有没有能通过的缺口,如果有,由数学关系可以得到也是横纵坐标绝对值差。如果不在的话就只能选择离端点最近的一个位置走。
如何判断呢,先将缺口排序,然后定义Len为x1,x2的中点,二分找离他最近的缺口pos,如果x1->x2内的话,直接走。否则判断一下它距离哪一个端点近,就由哪里绕过去。但是此时的pos值不一定准确,但十分接近,真实值一定出现在pos-1,pos,pos+1中。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #define MAXN 100010UL 2 3 #include<cstdio> 4 #include<algorithm> 5 using namespace std; 6 int n,m; 7 int a[MAXN]; 8 9 10 11 int jued(int a,int b){ 12 a=a-b; 13 if(a<0) return -a; 14 else return a; 15 } 16 17 int MIN(int a,int b){ 18 if(a<b) return a; 19 else return b; 20 } 21 22 int erfen(int g){ 23 int l=1,r=n; 24 int osc=n; 25 while(l<=r){ 26 int mid=(l+r)/2; 27 if(a[mid]<g) l=mid+1; 28 else r=mid-1,osc=mid; 29 } 30 return osc; 31 } 32 int main(){ 33 int x1,x2,y1,y2; 34 scanf("%d",&n); 35 for(int i=1;i<=n;i++){ 36 scanf("%d",&a[i]); 37 } 38 sort(a+1,a+n+1); 39 scanf("%d",&m); 40 for(int i=1;i<=m;i++){ 41 scanf("%d%d%d%d",&x1,&y1,&x2,&y2); 42 if((y1<0&&y2<0)||(y1>0&&y2>0)){ 43 printf("%d\n",jued(y1,y2)+jued(x1,x2)); 44 continue; 45 } 46 if(x1>x2) { 47 swap(x1,x2); 48 } 49 int len=(x1+x2)/2; 50 int pos=erfen(len); 51 if(a[pos]>=x1&&a[pos]<=x2) { 52 printf("%d\n",jued(y1,y2)+jued(x1,x2)); 53 } 54 else{ 55 int t1=jued(a[pos],x1)+jued(a[pos],x2)+jued(y1,y2),t2=0x7fffffff,t3=0x7fffffff; 56 if(pos>1){ 57 t2=jued(a[pos-1],x1)+jued(a[pos-1],x2)+jued(y1,y2); 58 } 59 if(pos<n){ 60 t3=jued(a[pos+1],x1)+jued(a[pos+1],x2)+jued(y1,y2); 61 } 62 if(t1>t2) t1=t2; 63 if(t1>t3) t1=t3; 64 printf("%d\n",t1); 65 } 66 } 67 }