SJY摆棋子【K-D Tree+常数优化】

题目链接


  首先,对于T==2的时候,查询是个很好解决的问题,关键就是在于插入怎么处理了。

  我们像做一个可持久化数据结构一样,我们对KD-Tree也进行可持久化,然后问题就变成了每次插入一个点,但是这样以来就是会使得查询的时候,我们的估值函数应该如何处理呢?

  估值函数的处理,就是对于每个区间段,处理出来它的区间的最值范围,最小值和最大值,然后呢,对于最近可能的曼哈顿距离,如此求解:

int fx(int rt)
{
    if(!rt) return INF;
    int sum = 0;
    for(int i=0; i<K; i++) sum += max(0, mn[rt][i] - q.d[i]) + max(0, q.d[i] - mx[rt][i]);
    return sum;
}

  将原来的点集看成了区间,只有在这个区间外面才有值。

  这道题的问题并不在于此,还有就是常数问题。

  如果把这题的空间像正常线段树一样开4倍是不可以的,也是会TLE的,内存占用过大了吧。所以,有多少个点就开多少个。这是一个优化。

  还有,这道题的读入很大,不妨使用快速读入来加速优化。

#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <bitset>
//#include <unordered_map>
//#include <unordered_set>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 0x3f3f3f3f
#define eps 1e-8
#define HalF (l + r)>>1
#define lsn rt<<1
#define rsn rt<<1|1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define myself rt, l, r
#define MP(a, b) make_pair(a, b)
using namespace std;
typedef unsigned long long ull;
typedef unsigned int uit;
typedef long long ll;
inline int read()
{
    int x=0; char c = getchar();
    while (c<'0' || c>'9') c = getchar();
    while (c>='0'&&c<='9') { x = x*10+c-'0';c = getchar(); }
    return x;
}
const int maxK = 2, maxN = 1e6 + 7, K = 2;
int N, M, op;
struct node
{
    int d[maxK]; int id;
    node(int a=0, int b=0, int c=0):d{a, b}, id(c) {}
    friend bool operator < (node e1, node e2) { return e1.d[op] < e2.d[op]; }
    void In() { for(int i=0; i<K; i++) d[i] = read(); }
} a[maxN], b[maxN];
inline bool cmp(node e1, node e2) { return e1.d[op] < e2.d[op]; }
node q, point;
int dis(node a, node b)
{
    int sum = 0;
    for(int i=0; i<K; i++) sum += abs(a.d[i] - b.d[i]);
    return sum;
}
node tree[maxN];
int lc[maxN], rc[maxN], tot, root;
int mx[maxN][maxK], mn[maxN][maxK];
int key[maxN];
double var[maxN];
int ans;
int fx(int rt)
{
    if(!rt) return INF;
    int sum = 0;
    for(int i=0; i<K; i++) sum += max(0, mn[rt][i] - q.d[i]) + max(0, q.d[i] - mx[rt][i]);
    return sum;
}
inline void pushup(int rt)
{
    for(int i=0; i<K; i++)
    {
        if(lc[rt] && rc[rt])
        {
            mn[rt][i] = min(tree[rt].d[i], min(mn[lc[rt]][i], mn[rc[rt]][i]));
            mx[rt][i] = max(tree[rt].d[i], max(mx[lc[rt]][i], mx[rc[rt]][i]));
        }
        else if(lc[rt])
        {
            mn[rt][i] = min(tree[rt].d[i], mn[lc[rt]][i]);
            mx[rt][i] = max(tree[rt].d[i], mx[lc[rt]][i]);
        }
        else if(rc[rt])
        {
            mn[rt][i] = min(tree[rt].d[i], mn[rc[rt]][i]);
            mx[rt][i] = max(tree[rt].d[i], mx[rc[rt]][i]);
        }
        else mn[rt][i] = mx[rt][i] = tree[rt].d[i];
    }
}
void build(int &rt, int l, int r, int P)
{
    if(l > r) return;
    int mid = HalF; rt = mid;
    key[rt] = P; op = P;
    nth_element(a + l, a + mid, a + r + 1, cmp);
    tree[rt] = a[mid];
    build(lc[rt], l, mid - 1, P ^ 1); build(rc[rt], mid + 1, r, P ^ 1);
    pushup(rt);
}
void Insert(int &rt, int P)
{
    if(!rt)
    {
        rt = ++tot;
        tree[rt] = q;
        key[rt] = P;
    }
    else Insert((q.d[key[rt]] < tree[rt].d[key[rt]] ? lc[rt] : rc[rt]), P ^ 1);
    pushup(rt);
}
void query(int rt)
{
    if(!rt) return;
    int dist = dis(q, tree[rt]);
    if(dist < ans)
    {
        ans = dist;
    }
    int dl = fx(lc[rt]), dr = fx(rc[rt]);
    if(dl < dr)
    {
        if(dl < ans) query(lc[rt]);
        if(dr < ans) query(rc[rt]);
    }
    else
    {
        if(dr < ans) query(rc[rt]);
        if(dl < ans) query(lc[rt]);
    }
}
int main()
{
    N = read(); M = read();
    for(int i=1; i<=N; i++)
    {
        a[i].In();
        a[i].id = i;
        b[i] = a[i];
    }
    build(root, 1, N, 0);
    tot = N;
    for(int i=1, op; i<=M; i++)
    {
        op = read();
        q.In(); q.id = N + i;
        if(op == 1)
        {
            Insert(root, 0);
        }
        else
        {
            ans = INF;
            query(root);
            printf("%d\n", ans);
        }
    }
    return 0;
}
发布了884 篇原创文章 · 获赞 1057 · 访问量 12万+

猜你喜欢

转载自blog.csdn.net/qq_41730082/article/details/105089535