【JZOJ 1792】教主的花园(二分)

版权声明:嗯随意转载吧,注明出处就好 https://blog.csdn.net/Fallen_Angel001/article/details/79284439

问题描述
【问题背景】
  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),并且这些点均不在屏障上,询问从一个点走到另一个点最短距离是多少,每次只能从一个格子走到相邻的格子。
输入
 输入的第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
算法讨论
如果两个点在一侧的话,直接算就行
如果不在一侧,先排序然后二分查找,假如能找到一个入口k使得x1<=k<=x2,那么结果就是
abs(x1-x2)+abs(y1-y2)
找不到就从选择到x1或者到x2最小的一个k
如果k

#include <cstdio>
#include <algorithm>
using namespace std;
#define maxn 100006
#define maxlongint 2147483647
int a[maxn],n,m,s,x1,y1,x2,y2,minn;
bool f;

int abs(int a)
{
    return a>0?a:-a;
}

bool half()
{
    int l=1,r=n,mid;
    while (l<=r)
    {
        mid=(l+r) / 2;
        if (a[mid]>=x1 && a[mid]<=x2 || a[mid]>=x2 && a[mid]<=x1)
        {
            f=1;
            return 1;
        }
        if (a[mid]<x1 && a[mid]<x2)
        {
            if (abs(a[mid]-x1)<minn)
                minn=abs(a[mid]-x1);
            if (abs(a[mid]-x2)<minn)
                minn=abs(a[mid]-x2);
            l=mid+1;
        }
        if (a[mid]>x1 && a[mid]>x2)
        {
            if (abs(a[mid]-x1)<minn)
                minn=abs(a[mid]-x1);
            if (abs(a[mid]-x2)<minn)
                minn=abs(a[mid]-x2);
            r=mid-1;
        }
    }
    return 0;
}

int main()
{
    scanf("%d",&n);
    for (int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    sort(a+1,a+n+1);
    scanf("%d",&m);
    while (m--)
    {
        minn=maxlongint; f=0; s=0;
        scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
        s+=abs(y2-y1);
        if (y1>0 && y2>0 || y1<0 && y2<0)
        {
            printf("%d\n",s+abs(x2-x1));
            continue;
        }
        if (half() && f)
            s+=abs(x2-x1);
        if (!f)
            s+=(2*minn+abs(x2-x1));
        printf("%d\n",s);
    }
}
阅读更多

没有更多推荐了,返回首页