NAIPC2018 Zoning Houses(ST表)

题目描述

Given a registry of all houses in your state or province, you would like to know the minimum size of an axis-aligned square zone such that every house in a range of addresses lies in the zone or on its border. The zoning is a bit lenient and you can ignore any one house from the range to make the zone smaller.
The addresses are given as integers from 1..n. Zoning requests are given as a consecutive range of houses. A valid zone is the smallest axis-aligned square that contains all of the points in the range,ignoring at most one.
Given the (x, y) locations of houses in your state or province, and a list of zoning requests, you must figure out for each request: What is the length of a side of the smallest axis-aligned square zone that contains all of the houses in the zoning request, possibly ignoring one house?

 

输入

Each input will consist of a single test case. Note that your program may be run multiple times on different inputs. Each test case will begin with a line containing two integers n and q (1 ≤ n, q ≤ 105 ), where n is the number of houses, and q is the number of zoning requests.
The next n lines will each contain two integers, x and y (−109 ≤ x, y ≤ 109 ), which are the (x,y) coordinates of a house in your state or province. The address of this house corresponds with the order in the input. The first house has address 1, the second house has address 2, and so on. No two houses will be at the same location.
The next q lines will contain two integers a and b (1 ≤ a < b ≤ n), which represents a zoning request for houses with addresses in the range [a..b] inclusive.

 

输出

Output q lines. On each line print the answer to one of the zoning requests, in order: the side length of the smallest axis-aligned square that contains all of the points of houses with those addresses, if at most one house can be ignored.

 

样例输入

3 2
1 0
0 1
1000 1
1 3
2 3

 

样例输出

1
0

 

题目大意是说给你N个点的坐标,有Q次询问,每次询问求能覆盖[l,r]区间内的所有点(可忽略一个点)的最小正方形的边长

因为忽略一个点肯定等于或者优于不忽略一个点,所以我们就每次都忽略一个点,这个点一定是横坐标最大、横坐标最小、纵坐标最大、纵坐标最小的四个点之一,所以我们每次枚举这四种情况,对每种情况求删除一个点后的最小正方形的边长。开始我用线段树写,一直1200msT到绝望,后来一问奕神才想到ST表...还是我太菜了...

#include <bits/stdc++.h>
using namespace std;
const int maxn = 100010;
struct fun
{
    int i,val;
};
int n;
fun xmax[maxn][20],xmin[maxn][20],ymax[maxn][20],ymin[maxn][20];
int logg[maxn];
int poww[20];
fun maxx(fun a, fun b)
{
    if (a.val > b.val)
        return a;
    return b;
}
fun minn(fun a, fun b)
{
    if (a.val < b.val)
        return a;
    return b;
}
void init() // 初始化ST表,求每个区间内的X/Y的最大/最小值和编号
{
    poww[0] = 1;
    for (int i = 1; i < 20; i++)
        poww[i] = poww[i - 1] << 1;
    for (int i = 2; i <= n; i++)
        logg[i] = logg[i >> 1] + 1;
    int tmpp = 1;
    for (int j = 1; j <= logg[n]; j++)
    {
        for (int i = 1; i <= n - tmpp - tmpp + 1; i++)
            xmax[i][j] = maxx(xmax[i][j - 1], xmax[i + tmpp][j - 1]);
        tmpp <<= 1;
    }
    tmpp = 1;
    for (int j = 1; j <= logg[n]; j++)
    {
        for (int i = 1; i <= n - tmpp - tmpp + 1; i++)
            ymax[i][j] = maxx(ymax[i][j - 1], ymax[i + tmpp][j - 1]);
        tmpp <<= 1;
    }
    tmpp = 1;
    for (int j = 1; j <= logg[n]; j++)
    {
        for (int i = 1; i <= n - tmpp - tmpp + 1; i++)
            xmin[i][j] = minn(xmin[i][j - 1], xmin[i + tmpp][j - 1]);
        tmpp <<= 1;
    }
    tmpp = 1;
    for (int j = 1; j <= logg[n]; j++)
    {
        for (int i = 1; i <= n - tmpp - tmpp + 1; i++)
            ymin[i][j] = minn(ymin[i][j - 1], ymin[i + tmpp][j - 1]);
        tmpp <<= 1;
    }
}
inline int doit(int l, int r, int z) //在[l,r]区间内删去z点
{
    int xxmax,xxmin,yymax,yymin; //删去删去一个点后剩下的点中横坐标最大/小值,纵坐标最大/小值
    if (z == l)
    {
        l++;
        int tmpp = logg[r - l + 1];
        xxmax = maxx(xmax[l][tmpp], xmax[r - poww[tmpp] + 1][tmpp]).val;
        xxmin = minn(xmin[l][tmpp], xmin[r - poww[tmpp] + 1][tmpp]).val;
        yymax = maxx(ymax[l][tmpp], ymax[r - poww[tmpp] + 1][tmpp]).val;
        yymin = minn(ymin[l][tmpp], ymin[r - poww[tmpp] + 1][tmpp]).val;
        return max(xxmax - xxmin, yymax - yymin);
    }
    if (z == r)
    {
        r--;
        int tmpp = logg[r - l + 1];
        xxmax = maxx(xmax[l][tmpp], xmax[r - poww[tmpp] + 1][tmpp]).val;
        xxmin = minn(xmin[l][tmpp], xmin[r - poww[tmpp] + 1][tmpp]).val;
        yymax = maxx(ymax[l][tmpp], ymax[r - poww[tmpp] + 1][tmpp]).val;
        yymin = minn(ymin[l][tmpp], ymin[r - poww[tmpp] + 1][tmpp]).val;
        return max(xxmax - xxmin, yymax - yymin);
    }
    int rr,ll;
    rr = r;
    ll = z + 1;
    r = z - 1;
    int tmpp = logg[r - l + 1];
    int tm = logg[rr - ll + 1];
    xxmax = max(maxx(xmax[l][tmpp], xmax[r - poww[tmpp] + 1][tmpp]).val,
                maxx(xmax[ll][tm], xmax[rr - poww[tm] + 1][tm]).val);
    xxmin = min(minn(xmin[l][tmpp], xmin[r - poww[tmpp] + 1][tmpp]).val,
                 minn(xmin[ll][tm], xmin[rr - poww[tm] + 1][tm]).val);
    yymax = max(maxx(ymax[l][tmpp], ymax[r - poww[tmpp] + 1][tmpp]).val,
                maxx(ymax[ll][tm], ymax[rr - poww[tm] + 1][tm]).val);
    yymin = min(minn(ymin[l][tmpp], ymin[r - poww[tmpp] + 1][tmpp]).val,
                minn(ymin[ll][tm], ymin[rr - poww[tm] + 1][tm]).val);
    return max(xxmax - xxmin, yymax - yymin);
}
int main()
{
//    freopen("in.txt", "r", stdin);
    int q,x,y;
    scanf("%d%d", &n, &q);
    for (int i = 1; i <= n; i++)
    {
        scanf("%d%d", &x, &y);
        xmax[i][0].val = xmin[i][0].val = x;
        ymax[i][0].val = ymin[i][0].val = y;
        xmax[i][0].i = xmin[i][0].i = ymax[i][0].i = ymin[i][0].i = i;
    }
    init();
    while (q--)
    {
        int l,r;
        scanf("%d%d", &l, &r);
        int tmpp = logg[r - l + 1];
        int xx,xy,yx,yy;
        xx = maxx(xmax[l][tmpp], xmax[r - poww[tmpp] + 1][tmpp]).i; //横坐标最大的点的编号
        xy = minn(xmin[l][tmpp], xmin[r - poww[tmpp] + 1][tmpp]).i; //横坐标最小的点的编号
        yx = maxx(ymax[l][tmpp], ymax[r - poww[tmpp] + 1][tmpp]).i; //纵坐标最大的点的编号
        yy = minn(ymin[l][tmpp], ymin[r - poww[tmpp] + 1][tmpp]).i; //纵坐标最小的点的编号
        int minn = doit(l, r, xx);  //删去横坐标最大的点
        minn = min(minn, doit(l, r, xy)); //删去横坐标最小的点
        minn = min(minn, doit(l, r, yx)); //删去纵坐标最大的点
        minn = min(minn, doit(l, r, yy)); //删去纵坐标最小的点
        printf("%d\n", minn);
    }
    return 0;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值