[Violet]天使玩偶/SJY摆棋子——k-d tree & Scapegoat tree

本文详细介绍了BZOJ2648-SJY摆棋子问题的在线解法,利用k-d树结合scapegoattree维护平衡,实现动态查询离某点曼哈顿距离最近的点。代码示例展示了具体的实现细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

BZOJ 2648-SJY摆棋子

题目大意

一堆点,可以加点,询问离某个点曼哈顿距离最近的点的曼哈顿距离

Solution

离线做法:cdq分治,代码量蛮短的

这里主要讲在线做法
这是k-d tree的模板题,但是因为有加点操作,所以不能保证k-dtree的重量平衡,可能会使这棵BST的结构变得很难看,随便一卡就能卡掉

所以我们要加上Scapegoat tree来暴力维护它的相对平衡

Code

#include <cstdio>
#include <iostream>
#include <algorithm>
#define al 0.75
#define N 1000010
#define INF 0x3f3f3f3f

using namespace std;

int rub[N], WD, top, root, cur, ans;

struct Point {
    int x[2];
    Point(int X = 0, int Y = 0) {
        x[0] = X;
        x[1] = Y;
    }
    inline bool operator < (const Point &o) const {
        return x[WD] < o.x[WD];
    }
}p[N];

struct Node {
    int mi[2], mx[2], ls, rs, sz;
    Point p;
}tr[N];

inline int read() {
    char ch = getchar();
    int x = 0;
    while (!isdigit(ch)) ch = getchar();
    while (isdigit(ch)) {
        x = (x << 1) + (x << 3) + (ch ^ 48);
        ch = getchar();
    }
    return x;
}

inline int newNode() {
    if (top) return rub[top--];
    return ++cur;
}

inline void pushup(int k) {
    int l = tr[k].ls, r = tr[k].rs;
    for (int i = 0; i < 2; ++i) {
        tr[k].mi[i] = tr[k].mx[i] = tr[k].p.x[i];
        if (l) {
            tr[k].mi[i] = min(tr[k].mi[i], tr[l].mi[i]);
            tr[k].mx[i] = max(tr[k].mx[i], tr[l].mx[i]);
        }
        if (r) {
            tr[k].mi[i] = min(tr[k].mi[i], tr[r].mi[i]);
            tr[k].mx[i] = max(tr[k].mx[i], tr[r].mx[i]);
        }
    }
    tr[k].sz = tr[l].sz + tr[r].sz + 1;
}

inline int build(int l, int r, int wd) {
    if (l > r) return 0;
    int k = newNode(), mid = l + r >> 1;
    WD = wd;
    nth_element(p + l, p + mid, p + r + 1);
    tr[k].p = p[mid];
    tr[k].ls = build(l, mid - 1, wd ^ 1);
    tr[k].rs = build(mid + 1, r, wd ^ 1);
    pushup(k);
    return k;
}

inline void pia(int k, int num) {
    if (tr[k].ls) pia(tr[k].ls, num);
    p[num + tr[tr[k].ls].sz + 1] = tr[k].p;
    rub[++top] = k;
    if (tr[k].rs) pia(tr[k].rs, num + tr[tr[k].ls].sz + 1);
}

inline void check(int &k, int wd) {
    if (al * tr[k].sz < tr[tr[k].ls].sz || al * tr[k].sz < tr[tr[k].rs].sz) {
        pia(k, 0);
        k = build(1, tr[k].sz, wd);
    }
}

inline void ins(Point now, int &k, int wd) {
    if (!k) {
        k = newNode();
        tr[k].p = now;
        tr[k].ls = tr[k].rs = 0;
        pushup(k);
        return;
    }
    if (tr[k].p.x[wd] < now.x[wd]) ins(now, tr[k].rs, wd ^ 1);
    else ins(now, tr[k].ls, wd ^ 1);
    pushup(k);
    check(k, wd);
}

inline int getdis(Point now, int k) {
    int ret = 0;
    for (int i = 0; i < 2; ++i) {
        ret += max(0, now.x[i] - tr[k].mx[i]) + max(0, tr[k].mi[i] - now.x[i]);
    }
    return ret;
}

inline int dis(Point a, Point b) {
    return abs(a.x[0] - b.x[0]) + abs(a.x[1] - b.x[1]);
}

inline void query(Point now, int k) {
    ans = min(ans, dis(now, tr[k].p));
    int dl = INF, dr = INF;
    if (tr[k].ls) dl = getdis(now, tr[k].ls);
    if (tr[k].rs) dr = getdis(now, tr[k].rs);
    if (dl < dr) {
        if (dl < ans) query(now, tr[k].ls);
        if (dr < ans) query(now, tr[k].rs);
    }
    else {
        if (dr < ans) query(now, tr[k].rs);
        if (dl < ans) query(now, tr[k].ls);
    }
}

int main() {
    int n = read(), m = read();
    for (int i = 1; i <= n; ++i) {
        p[i].x[0] = read();
        p[i].x[1] = read();
    }
    root = build(1, n, 0);
    while(m--) {
        int opt = read(), x = read(), y = read();
        if (opt == 1) ins(Point(x, y), root, 0);
        else ans = INF, query(Point(x, y), root), printf("%d\n", ans);
    }
    return 0;
}
onerror {resume} quietly WaveActivateNextPane {} 0 add wave -noupdate /tb_IBGT_Drive/s_clk add wave -noupdate /tb_IBGT_Drive/s_reset add wave -noupdate /tb_IBGT_Drive/shut_hv_2s add wave -noupdate /tb_IBGT_Drive/error_lamp add wave -noupdate /tb_IBGT_Drive/start_hv add wave -noupdate /tb_IBGT_Drive/starting_hv add wave -noupdate /tb_IBGT_Drive/stage1_hv add wave -noupdate /tb_IBGT_Drive/hvs2_elapsed_2s_q add wave -noupdate /tb_IBGT_Drive/charging_signal add wave -noupdate /tb_IBGT_Drive/sample_signal add wave -noupdate /tb_IBGT_Drive/igbt_drive add wave -noupdate /tb_IBGT_Drive/clk_1ms add wave -noupdate /tb_IBGT_Drive/en add wave -noupdate -color Green /tb_IBGT_Drive/seq_charging_A add wave -noupdate /tb_IBGT_Drive/charging_signal_dbc add wave -noupdate /tb_IBGT_Drive/charging_sensor add wave -noupdate /tb_IBGT_Drive/charging_sensor_dbc add wave -noupdate -color Violet -radix unsigned /tb_IBGT_Drive/pulse_inst/tick add wave -noupdate -color Violet -radix unsigned /tb_IBGT_Drive/pulse_inst/chg_num add wave -noupdate -color Violet -radix unsigned /tb_IBGT_Drive/pulse_inst/chg_interval add wave -noupdate -color Violet -radix unsigned /tb_IBGT_Drive/pulse_inst/chg_width add wave -noupdate -color Violet -radix unsigned /tb_IBGT_Drive/pulse_inst/chg_on add wave -noupdate -color Violet -radix unsigned /tb_IBGT_Drive/pulse_inst/sync_on add wave -noupdate -color Violet -radix unsigned /tb_IBGT_Drive/pulse_inst/sync_off add wave -noupdate -color Violet -radix unsigned /tb_IBGT_Drive/pulse_inst/dischg_on add wave -noupdate -color Violet -radix unsigned /tb_IBGT_Drive/pulse_inst/dischg_off add wave -noupdate -color Violet -radix unsigned /tb_IBGT_Drive/pulse_inst/mw_on add wave -noupdate -color Violet -radix unsigned /tb_IBGT_Drive/pulse_inst/mw_off add wave -noupdate -color Violet -radix unsigned /tb_IBGT_Drive/pulse_inst/counter add wave -noupdate -color Violet /tb_IBGT_Drive/pulse_inst/seq_sync add wave -noupdate -color Violet /tb_IBGT_Drive/pulse_inst/seq_microwave_on add wave -noupdate -color Violet /tb_IBGT_Drive/pulse_inst/seq_charging_A add wave -noupdate -color Violet /tb_IBGT_Drive/pulse_inst/seq_charging_B add wave -noupdate -color Violet /tb_IBGT_Drive/pulse_inst/dischg_choice add wave -noupdate -color Violet /tb_IBGT_Drive/pulse_inst/s_charging add wave -noupdate -color Violet /tb_IBGT_Drive/pulse_inst/s_discharging add wave -noupdate -color Violet -radix unsigned /tb_IBGT_Drive/pulse_inst/chg_num_r add wave -noupdate -color Violet -radix unsigned /tb_IBGT_Drive/pulse_inst/chg_interval_end add wave -noupdate -color Violet -radix unsigned /tb_IBGT_Drive/pulse_inst/chg_width_end add wave -noupdate -color Violet /tb_IBGT_Drive/pulse_inst/s_sync add wave -noupdate -color Violet -radix unsigned /tb_IBGT_Drive/pulse_inst/dischg_start add wave -noupdate -color Violet -radix unsigned /tb_IBGT_Drive/pulse_inst/dischg_end add wave -noupdate -color Violet -radix unsigned /tb_IBGT_Drive/pulse_inst/sample_start add wave -noupdate -color Violet -radix unsigned /tb_IBGT_Drive/pulse_inst/sample_end add wave -noupdate -color Violet -radix unsigned /tb_IBGT_Drive/pulse_inst/mw_start add wave -noupdate -color Violet -radix unsigned /tb_IBGT_Drive/pulse_inst/mw_end add wave -noupdate -color Violet -radix unsigned /tb_IBGT_Drive/pulse_inst/sync_start add wave -noupdate -color Violet -radix unsigned /tb_IBGT_Drive/pulse_inst/sync_end add wave -noupdate -color Cyan -radix unsigned /tb_IBGT_Drive/IGBT_DRIVE_inst/max_chg_width add wave -noupdate -color Cyan /tb_IBGT_Drive/IGBT_DRIVE_inst/charging_signal add wave -noupdate -color Cyan /tb_IBGT_Drive/IGBT_DRIVE_inst/sample_signal add wave -noupdate -color Cyan /tb_IBGT_Drive/IGBT_DRIVE_inst/chg_forbidden add wave -noupdate -color Cyan /tb_IBGT_Drive/IGBT_DRIVE_inst/igbt_drive add wave -noupdate -color Violet /tb_IBGT_Drive/pulse_inst/s_microwave_on add wave -noupdate -color Violet /tb_IBGT_Drive/pulse_inst/seq_discharging_A add wave -noupdate -color Violet /tb_IBGT_Drive/pulse_inst/seq_discharging_B add wave -noupdate -color Cyan /tb_IBGT_Drive/IGBT_DRIVE_inst/w_2 add wave -noupdate -color Cyan -radix unsigned /tb_IBGT_Drive/IGBT_DRIVE_inst/fall_delay add wave -noupdate -color Cyan /tb_IBGT_Drive/IGBT_DRIVE_inst/en add wave -noupdate -color Cyan /tb_IBGT_Drive/IGBT_DRIVE_inst/charging_sensor add wave -noupdate -color Cyan /tb_IBGT_Drive/IGBT_DRIVE_inst/max_pulse_width add wave -noupdate -color Cyan /tb_IBGT_Drive/IGBT_DRIVE_inst/rise_cap add wave -noupdate -color Cyan /tb_IBGT_Drive/IGBT_DRIVE_inst/rise add wave -noupdate -color Cyan /tb_IBGT_Drive/IGBT_DRIVE_inst/chg_fall_cap add wave -noupdate -color Cyan /tb_IBGT_Drive/IGBT_DRIVE_inst/fall_cap add wave -noupdate -color Cyan /tb_IBGT_Drive/IGBT_DRIVE_inst/fall add wave -noupdate -color Cyan /tb_IBGT_Drive/IGBT_DRIVE_inst/chg_fall add wave -noupdate -color Cyan /tb_IBGT_Drive/IGBT_DRIVE_inst/ending add wave -noupdate -color Cyan /tb_IBGT_Drive/IGBT_DRIVE_inst/sample add wave -noupdate -color Cyan -radix unsigned /tb_IBGT_Drive/IGBT_DRIVE_inst/mag_cnt add wave -noupdate -color Cyan -radix unsigned /tb_IBGT_Drive/IGBT_DRIVE_inst/sample_forbidden add wave -noupdate -color Cyan -radix unsigned /tb_IBGT_Drive/IGBT_DRIVE_inst/charing_cnt TreeUpdate [SetDefaultTree] WaveRestoreCursors {{Cursor 6} {58675767 ns} 0} quietly wave cursor active 1 configure wave -namecolwidth 299 configure wave -valuecolwidth 100 configure wave -justifyvalue left configure wave -signalnamewidth 0 configure wave -snapdistance 10 configure wave -datasetprefix 0 configure wave -rowmargin 4 configure wave -childrowmargin 2 configure wave -gridoffset 0 configure wave -gridperiod 1 configure wave -griddelta 40 configure wave -timeline 0 configure wave -timelineunits ns update WaveRestoreZoom {35484683 ns} {74949143 ns} 这是在做什么?
07-13
一、综合实战&mdash;使用极轴追踪方式绘制信号灯 实战目标:利用对象捕捉追踪和极轴追踪功能创建信号灯图形 技术要点:结合两种追踪方式实现精确绘图,适用于工程制图中需要精确定位的场景 1. 切换至AutoCAD 操作步骤: 启动AutoCAD 2016软件 打开随书光盘中的素材文件 确认工作空间为&quot;草图与注释&quot;模式 2. 绘图设置 1)草图设置对话框 打开方式:通过&quot;工具&rarr;绘图设置&quot;菜单命令 功能定位:该对话框包含捕捉、追踪等核心绘图辅助功能设置 2)对象捕捉设置 关键配置: 启用对象捕捉(F3快捷键) 启用对象捕捉追踪(F11快捷键) 勾选端点、中心、圆心、象限点等常用捕捉模式 追踪原理:命令执行时悬停光标可显示追踪矢量,再次悬停可停止追踪 3)极轴追踪设置 参数设置: 启用极轴追踪功能 设置角度增量为45度 确认后退出对话框 3. 绘制信号灯 1)绘制圆形 执行命令:&quot;绘图&rarr;圆&rarr;圆心、半径&quot;命令 绘制过程: 使用对象捕捉追踪定位矩形中心作为圆心 输入半径值30并按Enter确认 通过象限点捕捉确保圆形位置准确 2)绘制直线 操作要点: 选择&quot;绘图&rarr;直线&quot;命令 捕捉矩形上边中点作为起点 捕捉圆的上象限点作为终点 按Enter结束当前直线命令 重复技巧: 按Enter可重复最近使用的直线命令 通过圆心捕捉和极轴追踪绘制放射状直线 最终形成完整的信号灯指示图案 3)完成绘制 验证要点: 检查所有直线是否准确连接圆心和象限点 确认极轴追踪的45度增量是否体现 保存绘图文件(快捷键Ctrl+S)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值