1. 程式人生 > >【LG4169】[Violet]天使玩偶/SJY擺棋子

【LG4169】[Violet]天使玩偶/SJY擺棋子

【LG4169】[Violet]天使玩偶/SJY擺棋子

題面

bzoj許可權題呀
良心洛谷

題解

其實題目就是說
實時插入點,並且給定點\((x,y)\)
\(min_{i=1}^{n}\)\({|x-x_i|+|y-y_i|}\)
絕對值很醜,其實可以分別考慮右上、左上、左下、右下四個方向
就可以把式子變成這樣
\(min_{i=1}^{n}\)\({(x-x_i)+(y-y_i)}\)
\(=>\) \((x+y)-max(x_i+y_i)\)其中\(x_i\)\(y_i\)分別小於\(x\)\(y\)
然後這個可以用值域樹狀陣列維護一個字首\(max\)來做
而四個方向直接將點按照座標軸對稱過去即可
程式碼
常數大,要吸氧

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <climits> 
using namespace std;
namespace IO { 
    const int BUFSIZE = 1 << 20; 
    char ibuf[BUFSIZE], *is = ibuf, *it = ibuf; 
    inline char gc() { 
        if (is == it) it = (is = ibuf) + fread(ibuf, 1, BUFSIZE, stdin); 
        return *is++; 
    } 
} 
inline int gi() {
    register int data = 0, w = 1;
    register char ch = 0;
    while (ch != '-' && (ch > '9' || ch < '0')) ch = IO::gc();
    if (ch == '-') w = -1 , ch = IO::gc();
    while (ch >= '0' && ch <= '9') data = data * 10 + (ch ^ 48), ch = IO::gc();
    return w * data;
}
inline void chkmin(int &x, int y) { if (x > y) x = y; } 
inline void chkmax(int &x, int y) { if (x < y) x = y; } 
#define MAX_V 1000005 
#define MAX_N 300005 
inline int lb(int x) { return x & -x; } 
int c[MAX_V], Lx = 0, Ly = 0; 
void clear(int x) { while (x <= Ly) c[x] = 0, x += lb(x); } 
int qmax(int x) { int res = 0; while (x > 0) chkmax(res, c[x]), x -= lb(x); return res; } 
void add(int x, int v) { while (x <= Ly) chkmax(c[x], v), x += lb(x); } 
struct Query { int t, x, y; bool fl; } q[MAX_N << 1]; int A[MAX_N << 1]; 
inline bool cmp_t(Query a, Query b) { return a.t < b.t; } 
inline bool cmp_x(Query a, Query b) { return (a.x == b.x) ? (a.y < b.y) : (a.x < b.x); } 
void Div(int l, int r) { 
    if (l == r) return ; 
    int mid = (l + r) >> 1; 
    Div(l, mid); Div(mid + 1, r); 
    int j = l; 
    for (int i = mid + 1; i <= r; i++) { 
        if (q[i].fl) continue; 
        for ( ; j <= mid && q[j].x <= q[i].x; ++j) 
            if (q[j].fl) add(q[j].y, q[j].x + q[j].y); 
        int res = qmax(q[i].y); if (res) chkmin(A[q[i].t], q[i].x + q[i].y - res); 
    } 
    for (int i = l; i < j; i++) if (q[i].fl) clear(q[i].y); 
    inplace_merge(&q[l], &q[mid + 1], &q[r + 1], cmp_x); 
} 
int N, M; 
void init() { sort(&q[1], &q[N + 1], cmp_t); } 
int main () { 
    N = gi(), M = gi(); 
    for (int i = 1; i <= N; i++) { 
        int x = gi() + 1, y = gi() + 1; 
        q[i] = (Query){i, x, y, 1}; 
        chkmax(Lx, x), chkmax(Ly, y); 
    } 
    while (M--) {
        int op = gi(), x = gi() + 1, y = gi() + 1; 
        ++N, q[N] = (Query){N, x, y, op & 1}; 
        chkmax(Lx, x), chkmax(Ly, y); 
    } 
    for (int i = 1; i <= N; i++) A[i] = INT_MAX; ++Lx, ++Ly; 
    Div(1, N); 
    for (int i = 1; i <= N; i++) q[i].x = Lx - q[i].x; init(); Div(1, N); 
    for (int i = 1; i <= N; i++) q[i].x = Lx - q[i].x;
    for (int i = 1; i <= N; i++) q[i].y = Ly - q[i].y; init(); Div(1, N); 
    for (int i = 1; i <= N; i++) q[i].y = Ly - q[i].y;
    for (int i = 1; i <= N; i++) q[i].x = Lx - q[i].x, q[i].y = Ly - q[i].y; init(); Div(1, N); 
    for (int i = 1; i <= N; i++) 
        if (A[i] != INT_MAX) printf("%d\n", A[i]); 
    return 0; 
}