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

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

题面

bzoj权限题呀

良心洛谷

题解

cdq分治

其实题目就是说

实时插入点,并且给定点\((x,y)\)

\(min_{i=1}^{n}\)\({|x-x_i|+|y-y_i|}\)

我们考虑\(cdq\)分治,如何做呢?

绝对值很丑,其实可以分别考虑右上、左上、左下、右下四个方向

就可以把式子变成这样

\(min_{i=1}^{n}\)\({(x-x_i)+(y-y_i)}\)

\(\Rightarrow\) \((x+y)-max(x_i+y_i)\)其中\(x_i\)\(y_i\)分别小于\(x\)\(y\)

然后这个可以用值域树状数组维护一个前缀\(max\)来做

而四个方向直接将点按照坐标轴对称过去即可

代码

常数大,要吸氧

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

KDtree

这里

转载于:https://www.cnblogs.com/heyujun/p/10120747.html

你可能感兴趣的:(数据结构与算法)