jzoj1792 教主的花园 (二分)

教主的花园 (Standard IO)

Description

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

【问题描述】
  可以把教主的花园附近区域抽像成一个正方形网格组成的网络,每个网格都对应了一个坐标(均为整数,有可能为负),若两个网格(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),并且这些点均不在屏障上,询问从一个点走到另一个点最短距离是多少,每次只能从一个格子走到相邻的格子。

Input

  输入的第1行为一个正整数N,为屏障上入口的个数。
  第2行有N个整数,a1, a2, …, aN,之间用空格隔开,为这N个入口的横坐标。
  第3行为一个正整数M,表示了M个询问。
  接下来M行,每行4个整数x1, y1, x2, y2,有y1与y2均不等于0,表示了一个询问从(x1, y1)到(x2, y2)的最短路。

Output

  输出共包含m行,第i行对于第i个询问输出从(x1, y1)到(x2, y2)的最短路距离是多少。

Sample Input

2
2 -1
2
0 1 0 -1
1 1 2 2

Sample Output

4
2

Data Constraint

Hint

【数据规模】
  对于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。
  
分析:如果两个点在一侧的话,直接算就行
如果不在一侧,先排序然后二分查找,假如能找到一个入口k使得x1<=k<=x2,那么结果就是
abs(x1-x2)+abs(y1-y2)
找不到就从选择到x1或者到x2最小的一个k
如果 k < x1,那么就writeln(abs(x1-x2)+abs(y1-y2)+abs(x1-k)*2)
如果k>x2,那就writeln(abs(x1-x2)+abs(y1-y2)+abs(x2-k)*2)

代码

#include <cstdio>
#include <algorithm>
#define ll long long
#define N 100005
using namespace std;

int n,m,a[N];

ll fabs(ll x){return x>0?x:-x;} 
ll min(ll x,ll y){return x<y?x:y;}

ll getsum(ll x1,ll y1,ll x2,ll y2)
{
    int s=0; 
    if (x1>x2) s+=x1-x2;else s+=x2-x1;
    if (y1>y2) s+=y1-y2;else s+=y2-y1;
    return s;
}

int find1(ll x)
{
    int l=1,r=n;
    int ans=n;
    while (l<=r)
    {
        int mid=(l+r)/2;
        if (a[mid]==x) return mid;
        if (x>=a[mid]) l=mid+1,ans=mid;
            else r=mid-1;
    }
    return ans;
}

int find2(ll x)
{
    int l=1,r=n;
    int ans=n;
    while (l<=r)
    {
        int mid=(l+r)/2;
        if (a[mid]==x) return mid;
        if (a[mid]>=x) r=mid-1,ans=mid;
            else l=mid+1;
    }
    return ans;
}

int main()
{
    freopen("1.in","r",stdin);
    scanf("%d",&n);
    for (int i=1;i<=n;i++)
        scanf("%lld",&a[i]);
    sort(a+1,a+n+1);
    scanf("%d",&m);
    for (int i=1;i<=m;i++)
    {
        ll x1,y1,x2,y2;
        scanf("%lld%lld%lld%lld",&x1,&y1,&x2,&y2);
        if (x1>x2)
        {
            x1^=x2;x2^=x1;x1^=x2;
            y1^=y2;y2^=y1;y1^=y2;
        }
        if ((y1>0&&y2>0)||(y1<0&&y2<0))
        {
            printf("%lld\n",getsum(x1,y1,x2,y2));
            continue;
        }
        if (x1<=a[1])
        {
            printf("%d\n",abs(y2)+abs(y1)+abs(x1-a[1])+abs(x2-a[1]));
            continue;
        }
        if (x2>=a[n])
        {
            printf("%d\n",abs(y2)+abs(y1)+abs(x1-a[n])+abs(x2-a[n]));
            continue;
        }
        if (a[find2(x1)]<=x2)
        {
            printf("%d\n",getsum(x1,y1,x2,y2));
            continue;
        }
        int p1=find1(x1);
        int p2=find2(x2);
        ll ans;
        ans=x1-a[p1]+fabs(y1)+fabs(y2)+x2-a[p1];
        ans=min(ans,a[p2]-x2+fabs(y1)+fabs(y2)+a[p2]-x1);
        printf("%lld\n",ans);
    }
}

猜你喜欢

转载自blog.csdn.net/zhanghaoxian1/article/details/79283732