教主的花园

教主的花园

 

题目描述

     教主最近总困扰于前来膜拜他的人太多了,所以他给他的花园加上了一道屏障。

可以把教主的花园附近区域抽像成一个正方形网格组成的网络,每个网格都对应了一个坐标(均为整数,有可能为负),若两个网格(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中。

 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 }
View Code

 

posted @ 2015-10-11 18:29 Lenicodes 阅读( ...) 评论( ...) 编辑 收藏
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值