【LG4169】[Violet]天使玩偶/SJY擺棋子
阿新 • • 發佈:2018-12-14
【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; }