CF 314D Sereja and Straight Lines(旋转坐标轴+二分)

题目链接:http://codeforces.com/problemset/problem/314/D

题意:给出平面上一些点的坐标。在平面上画两个相互垂直的直线,且已知一条与x轴夹角45度。画完之后,使得点到直线的距离的最大值最小。距离为|x1-x2|+|y1-y2|。

思路:(1)首先,将坐标轴旋转45度,那么点(x,y)的坐标变为(x-y,x+y)。然后就是画出两条分别平行于xy轴的直线使得距离的最大值最小。其实就是画出一个最小的正方形包含所有点。

(2)我们将所有点按照x升序,用preMin[i],preMax[i]表示前i个点最小、最大的y坐标;sufMin[i]、sufMax[i]表示后i个点最小最大的y坐标。

(3)二分答案d(正方形的边长),对于中间一段的点[j,i](i和j的横坐标差小于等于d),那么我们只要j-1之前和i+1之后的y的最大最小差值在d之内就可以。每次判断可行性O(n)


pair<int,int> a[N];
int n;
int preMin[N],preMax[N],sufMin[N],sufMax[N];


int OK(i64 d)
{
    int i,j=1,y1,y2;
    FOR1(i,n)
    {
        while(a[i].first>a[j].first+d) j++;
        y1=max(sufMax[i+1],preMax[j-1]);
        y2=min(sufMin[i+1],preMin[j-1]);
        if(y1-y2<=d) return 1;
    }
    return 0;
}

int main()
{
    RD(n);
    int i,x,y;
    FOR1(i,n)
    {
        RD(x,y);
        a[i]=MP(x-y,x+y);
    }
    sort(a+1,a+n+1);
    preMin[0]=INF;
    preMax[0]=-INF;
    FOR1(i,n)
    {
        preMin[i]=min(preMin[i-1],a[i].second);
        preMax[i]=max(preMax[i-1],a[i].second);
    }
    sufMin[n+1]=INF;
    sufMax[n+1]=-INF;
    FORL1(i,n)
    {
        sufMin[i]=min(sufMin[i+1],a[i].second);
        sufMax[i]=max(sufMax[i+1],a[i].second);
    }
    i64 low=0,high=inf,mid,ans;
    while(low<=high)
    {
        mid=(low+high)>>1;
        if(OK(mid)) ans=mid,high=mid-1;
        else low=mid+1;
    }
    PR(ans/2.0);
    return 0;
}

你可能感兴趣的:(in)