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;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章