[BZOJ1941][SDOI2010]Hide and Seek(线段树)

来源:互联网 发布:关系型数据库基本特征 编辑:程序博客网 时间:2024/06/04 20:10

可以发现,对于任意两点ij,如果xixjyiyj,则在计算ij之间的曼哈顿距离时,可以去掉绝对值符号,移项后变为(xi+yi)(xj+yj)。可以发现如果离散化坐标之后点i的坐标为(ui,vi),则在点i左下角的所有点中,与i的最小和最大距离就相当于求满足对于任何一个ukui,vkvikixk+yk的最大和最小值。
首先按照x坐标排序。之后从左往右扫描,扫到一个点就把一个点插入线段树。这样对于当前到达的任何一个点i,已经插入线段树的点k一定有ukui。所以每遇到一个点i,就在vi的位置插入一个值xi+yi。当然,要在插入之前,询问[1,vi]的最小和最大值以更新答案。
同时,上面的操作只能算出一个点与其左下角的点的最短和最长距离。所以上面的操作要做4次,每次做完后把坐标图旋转90度。
代码:

#include <cmath>#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>#define p2 p << 1#define p3 p << 1 | 1using namespace std;inline int read() {    int res = 0; bool bo = 0; char c;    while (((c = getchar()) < '0' || c > '9') && c != '-');    if (c == '-') bo = 1; else res = c - 48;    while ((c = getchar()) >= '0' && c <= '9')        res = (res << 3) + (res << 1) + (c - 48);    return bo ? ~res + 1 : res;}const int N = 1e5 + 5, INF = 0x3f3f3f3f;int n, Max[N << 2], Min[N << 2], disMax[N], disMin[N];struct cyx {int x, y, u, v, id;} a[N];bool comp1(cyx a, cyx b) {    if (a.x != b.x) return a.x < b.x;    return a.y < b.y;}bool comp2(cyx a, cyx b) {    if (a.y != b.y) return a.y < b.y;    return a.x < b.x;}void build(int l, int r, int p) {    if (l == r) {Max[p] = -INF; Min[p] = INF; return;}    int mid = l + r >> 1;    build(l, mid, p2); build(mid + 1, r, p3);    Max[p] = -INF; Min[p] = INF;}void change(int l, int r, int pos, int v, int p) {    if (l == r) {Max[p] = max(Max[p], v); Min[p] = min(Min[p], v); return;}    int mid = l + r >> 1; if (pos <= mid) change(l, mid, pos, v, p2);    else change(mid + 1, r, pos, v, p3);    Max[p] = max(Max[p2], Max[p3]);    Min[p] = min(Min[p2], Min[p3]);}int queryMax(int l, int r, int s, int e, int p) {    if (l == s && r == e) return Max[p];    int mid = l + r >> 1, res;    if (e <= mid) res = queryMax(l, mid, s, e, p2);    else if (s >= mid + 1) res = queryMax(mid + 1, r, s, e, p3);    else res = max(queryMax(l, mid, s, mid, p2),        queryMax(mid + 1, r, mid + 1, e, p3));    return res;}int queryMin(int l, int r, int s, int e, int p) {    if (l == s && r == e) return Min[p];    int mid = l + r >> 1, res;    if (e <= mid) res = queryMin(l, mid, s, e, p2);    else if (s >= mid + 1) res = queryMin(mid + 1, r, s, e, p3);    else res = min(queryMin(l, mid, s, mid, p2),        queryMin(mid + 1, r, mid + 1, e, p3));    return res;}void solve() {    int i; build(1, 1e5, 1);    for (i = 1; i <= n; i++) {        int maxd = a[i].x + a[i].y - queryMin(1, 1e5, 1, a[i].v, 1), mind;        mind = a[i].x + a[i].y - queryMax(1, 1e5, 1, a[i].v, 1);        change(1, 1e5, a[i].v, a[i].x + a[i].y, 1);        disMax[a[i].id] = max(disMax[a[i].id], maxd);        disMin[a[i].id] = min(disMin[a[i].id], mind);    }}void init() {    int i, tot = 0; sort(a + 1, a + n + 1, comp2);    for (i = 1; i <= n; i++) {        if (i == 1 || a[i].y != a[i - 1].y) tot++;        a[i].v = tot;    }    tot = 0; sort(a + 1, a + n + 1, comp1);    for (i = 1; i <= n; i++) {        if (i == 1 || a[i].x != a[i - 1].x) tot++;        a[i].u = tot;    }}int main() {    int i, j, res = INF; n = read();    for (i = 1; i <= n; i++) a[i].x = read() + 1,        a[i].y = read() + 1, a[i].id = i;    for (i = 1; i <= n; i++) disMax[i] = -INF, disMin[i] = INF;    for (j = 1; j <= 4; j++) {        init(); solve();        for (i = 1; i <= n; i++) swap(a[i].x, a[i].y),            a[i].x = 13e7 - a[i].x + 1;    }    for (i = 1; i <= n; i++) res = min(res, disMax[i] - disMin[i]);    return printf("%d\n", res), 0;}
原创粉丝点击