SJY摆棋子【替罪羊树重构K-D Tree】

题目链接 BZOJ 2648


  前N个点还是比较好处理的,直接利用二叉树的建树来进行处理,关键就是后面的不断插入的M个点,这时候该如何操作来降低复杂度?

  这里,我们引入替罪羊树的思想来使得二叉树趋于平衡,那么平衡因子应该如何确定呢?这道题存在一定的卡常,因为总的点数将近1e6了,这样以来,复杂度O(N * log(N))都不能带大常数了。

  所以,我们估一下值,大概在处理了3e5次操作之后就直接进行重构树,保证了生成的二叉树大致上是趋于矮胖矮胖的稳定型。

  为什么大致上是3e5呢?要是2e5的时候就重构会RE,递归次数太多了吧。

0 5
1 1 1
1 0 0
1 2 1
1 3 4
2 2 3
ans:2
#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 maxN = 1e6 + 7, maxK = 2, K = 2;
int N, M, op;
struct node
{
    int d[2];
    friend bool operator < (node e1, node e2) { return e1.d[op] < e2.d[op]; }
    friend bool operator == (node e1, node e2) { return e1.d[0] == e2.d[0] && e1.d[1] == e2.d[1]; }
    inline void In() { for(int i=0; i<K; i++) d[i] = read(); }
} a[maxN], tree[maxN], p;
int root, key[maxN], child[maxN][2], mx[maxN][maxK], mn[maxN][maxK], tot;
inline void pushup(int rt)
{
    for(int i=0; i<K; i++)
    {
        if(child[rt][0] && child[rt][1])
        {
            mx[rt][i] = max(tree[rt].d[i], max(mx[child[rt][0]][i], mx[child[rt][1]][i]));
            mn[rt][i] = min(tree[rt].d[i], min(mn[child[rt][0]][i], mn[child[rt][1]][i]));
        }
        else if(child[rt][0])
        {
            mx[rt][i] = max(tree[rt].d[i], mx[child[rt][0]][i]);
            mn[rt][i] = min(tree[rt].d[i], mn[child[rt][0]][i]);
        }
        else if(child[rt][1])
        {
            mx[rt][i] = max(tree[rt].d[i], mx[child[rt][1]][i]);
            mn[rt][i] = min(tree[rt].d[i], mn[child[rt][1]][i]);
        }
        else mx[rt][i] = mn[rt][i] = tree[rt].d[i];
    }
}
void build(int &rt, int l, int r, int father)
{
    if(l > r) return;
    int mid = HalF; rt = mid;
    key[rt] = key[father] ^ 1;
    op = key[rt];
    nth_element(a + l, a + mid, a + r + 1);
    tree[rt] = a[mid];
    build(child[rt][0], l, mid - 1, rt);
    build(child[rt][1], mid + 1, r, rt);
    pushup(rt);
}
bool did = false;
void Insert(int &rt, int fa)
{
    if(!rt)
    {
        rt = ++tot;
        tree[rt] = p;
        key[rt] = key[fa] ^ 1;
    }
    else
    {
        op = key[rt];
        Insert(child[rt][tree[rt] < p], rt);
    }
    pushup(rt);
}
inline 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;
}
inline int Fx(int rt)
{
    if(!rt) return INF;
    int sum = 0;
    for(int i=0; i<K; i++) sum += max(0, mn[rt][i] - p.d[i]) + max(0, p.d[i] - mx[rt][i]);
    return sum;
}
int ans;
void query(int rt)
{
    if(!rt) return;
    int dist = _Dis(tree[rt], p);
    if(dist < ans) ans = dist;
    int dl = Fx(child[rt][0]), dr = Fx(child[rt][1]);
    if(dl < dr)
    {
        if(dl < ans) query(child[rt][0]);
        if(dr < ans) query(child[rt][1]);
    }
    else
    {
        if(dr < ans) query(child[rt][1]);
        if(dl < ans) query(child[rt][0]);
    }
}
int main()
{
    N = read(); M = read();
    for(int i=1; i<=N; i++) a[i].In();
    key[0] = 0;
    build(root, 1, N, 0); tot = N;
    for(int i=1, t; i<=M; i++)
    {
        t = read();
        p.In();
        if(t == 1)
        {
            did = false;
            Insert(root, 0);
            if(did) a[tot] = p;
            if(i % 300000 == 0) build(root, 1, tot, 0);
        }
        else
        {
            ans = INF;
            query(root);
            printf("%d\n", ans);
        }
    }
    return 0;
}
发布了884 篇原创文章 · 获赞 1057 · 访问量 12万+

猜你喜欢

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