KDtree真的很妙啊,真的是又好写,作用还多,以后还需更多学习呀.

对于这道题,我们求的是曼哈顿距离的最小值.

而维护的变量和以往是相同的,就是横纵坐标的最小值与最大值.

我们设为一个极为巧妙且玄学的股价函数.

int getdis(int o,int x1,int y1){
int dis = 0;
if(x1 < node[o].minv[0]) dis += node[o].minv[0] - x1;
if(x1 > node[o].maxv[0]) dis += x1 - node[o].maxv[0];
if(y1 < node[o].minv[1]) dis += node[o].minv[1] - y1;
if(y1 > node[o].maxv[1]) dis += y1 - node[o].maxv[1];
return dis;
}
void query(int o,int x1,int y1){
int dn = abs(node[o].p[0] - x1) + abs(node[o].p[1] - y1),dl,dr;
ans = min(ans,dn);
dl = node[o].ch[0] ? getdis(node[o].ch[0],x1,y1) : inf;
dr = node[o].ch[1] ? getdis(node[o].ch[1],x1,y1) : inf;
if(dl < dr) {
if(dl < ans) query(node[o].ch[0],x1,y1);
if(dr < ans) query(node[o].ch[1],x1,y1);
}
else {
if(dr < ans) query(node[o].ch[1],x1,y1);
if(dl < ans) query(node[o].ch[0],x1,y1);
}
}  

设当前矩阵的边界为 (x1,y1),(x2,y2).

那么对于当前要查询的点 $p$ 如果在矩阵外,那么即使是最近距离也是 $p$ 到最近两个矩阵边界的曼哈顿距离和(getdis函数).

我们将上述最理想化距离设为 $w$,即点 $p$ 到矩阵边界的最小距离.

那么,如果点 $p$ 比当前最优解大的话,那么这一棵子树就没有必要查了.

Code:

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cstdlib>
#define setIO(s) freopen(s".in","r",stdin)
#define maxn 3000000
#define inf 100000000
using namespace std;
namespace KDtree{
int tot;
int d;
int ans;
int n;
int m;
void init(){ tot = n, ans = inf; }
int newnode(){ return ++tot; }
struct Data{
int ch[2],minv[2],maxv[2],w,sum,p[2];
}node[maxn];
bool cmp(Data i,Data j){
return i.p[d] == j.p[d] ? i.p[d^1] < j.p[d^1]: i.p[d] < j.p[d];
}
int isin(int o,int x1,int y1,int x2,int y2){
if(node[o].minv[0]>=x1&&node[o].maxv[0]<=x2&&node[o].minv[1]>=y1&&node[o].maxv[1]<=y2) return 1;
return 0;
}
int isout(int o,int x1,int y1,int x2,int y2){
if(node[o].minv[0] > x2 || node[o].maxv[0] < x1) return 1;
if(node[o].minv[1] > y2 || node[o].maxv[1] < y1) return 1;
return 0;
}
void getmax(int &a,int b){ if( b > a ) a = b; }
void getmin(int &a,int b){ if( b < a ) a = b; }
void pushup(int o,int x){
getmin(node[o].minv[0],node[x].minv[0]);
getmin(node[o].minv[1],node[x].minv[1]);
getmax(node[o].maxv[1],node[x].maxv[1]);
getmax(node[o].maxv[0],node[x].maxv[0]);
node[o].sum += node[x].sum;
}
int build(int l,int r,int o){
int mid = (l + r) >> 1;
d = o ; nth_element(node+l,node+mid,node+r+1,cmp);
node[mid].minv[0] = node[mid].maxv[0] = node[mid].p[0];
node[mid].minv[1] = node[mid].maxv[1] = node[mid].p[1];
node[mid].sum = node[mid].w;
node[mid].ch[0] = node[mid].ch[1] = 0;
if(l < mid) node[mid].ch[0] = build(l,mid - 1,o ^ 1), pushup(mid,node[mid].ch[0]);
if(r > mid) node[mid].ch[1] = build(mid + 1, r, o ^ 1), pushup(mid,node[mid].ch[1]);
return mid;
}
void update(int &o,Data x,int de){
if(!o) {
o = newnode();
node[o].p[0] = node[o].maxv[0] = node[o].minv[0] = x.p[0];
node[o].p[1] = node[o].minv[1] = node[o].maxv[1] = x.p[1];
return;
}
if(x.p[de] < node[o].p[de]) update(node[o].ch[0],x,de^1),pushup(o,node[o].ch[0]);
else update(node[o].ch[1],x,de^1),pushup(o,node[o].ch[1]);
}
int getdis(int o,int x1,int y1){
int dis = 0;
if(x1 < node[o].minv[0]) dis += node[o].minv[0] - x1;
if(x1 > node[o].maxv[0]) dis += x1 - node[o].maxv[0];
if(y1 < node[o].minv[1]) dis += node[o].minv[1] - y1;
if(y1 > node[o].maxv[1]) dis += y1 - node[o].maxv[1];
return dis;
}
void query(int o,int x1,int y1){
int dn = abs(node[o].p[0] - x1) + abs(node[o].p[1] - y1),dl,dr;
ans = min(ans,dn);
dl = node[o].ch[0] ? getdis(node[o].ch[0],x1,y1) : inf;
dr = node[o].ch[1] ? getdis(node[o].ch[1],x1,y1) : inf;
if(dl < dr) {
if(dl < ans) query(node[o].ch[0],x1,y1);
if(dr < ans) query(node[o].ch[1],x1,y1);
}
else {
if(dr < ans) query(node[o].ch[1],x1,y1);
if(dl < ans) query(node[o].ch[0],x1,y1);
}
}
int main(){
scanf("%d%d",&n,&m);
init();
for(int i = 1;i <= n; ++i) scanf("%d%d",&node[i].p[0],&node[i].p[1]);
int root = build(1,n,0);
for(int i = 1;i <= m; ++i) {
int opt,a,b;
scanf("%d%d%d",&opt,&a,&b);
if(opt == 1) {
Data k;
k.p[0] = a,k.p[1] = b;
update(root,k,0);
if(i % 300000 == 0) root = build(1,tot,0);
}
if(opt == 2) {
ans = inf;
query(root,a,b);
printf("%d\n",ans);
}
}
return 0;
}
};
int main(){
//setIO("input");
KDtree::main();
return 0;
}

  

bzoj 2648: SJY摆棋子 KDtree + 替罪羊式重构的更多相关文章

  1. BZOJ 2648: SJY摆棋子 kdtree

    2648: SJY摆棋子 题目连接: http://www.lydsy.com/JudgeOnline/problem.php?id=2648 Description 这天,SJY显得无聊.在家自己玩 ...

  2. bzoj 2648 SJY摆棋子——KDtree

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2648 第一道KDtree! 学习资料:https://blog.csdn.net/zhl30 ...

  3. BZOJ 2648 SJY摆棋子 ——KD-Tree

    [题目分析] KD-Tree第一题,其实大概就是搜索剪枝的思想,在随机数据下可以表现的非常好NlogN,但是特殊数据下会达到N^2. 精髓就在于估价函数get以及按照不同维度顺序划分的思想. [代码] ...

  4. bzoj 2648: SJY摆棋子&&2716: [Violet 3]天使玩偶 --kdtree

    2648: SJY摆棋子&&2716: [Violet 3]天使玩偶 Time Limit: 20 Sec  Memory Limit: 128 MB Description 这天,S ...

  5. BZOJ 2648: SJY摆棋子

    2648: SJY摆棋子 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 2968  Solved: 1011[Submit][Status][Disc ...

  6. bzoj 2648: SJY摆棋子【KD-tree】

    其实理论上cdq更优 核心是依次取x值.y值的mid作为当前节点,向两边递归建立二叉树,树上维护size:子树大小:mx[0/1]:子树内最大x/y:mn[0/1]:子树内最小x/y:d[0/1]:这 ...

  7. BZOJ 2648: SJY摆棋子(K-D Tree)

    Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 6051  Solved: 2113[Submit][Status][Discuss] Descript ...

  8. bzoj 2648 SJY摆棋子 kd树

    题目链接 初始的时候有一些棋子, 然后给两种操作, 一种是往上面放棋子. 另一种是给出一个棋子的位置, 问你离它最近的棋子的曼哈顿距离是多少. 写了指针版本的kd树, 感觉这个版本很好理解. #inc ...

  9. BZOJ 2648 SJY摆棋子(KD Tree)

    http://www.lydsy.com/JudgeOnline/problem.php?id=2648 题意: 思路: KDtree模板题. 参考自http://www.cnblogs.com/ra ...

随机推荐

  1. 【Git教程】Git教程之分支管理

      在前一篇文章中,主要针对Git本地仓库和远程仓库的基本操作命令进行了简要介绍,本文主要集中介绍Git的另一个主要的特点:分支管理和多人协作. 什么是分支管理   当一个任务需要多人协作完成时,每个 ...

  2. tsar采集数据原理

    系统模块 cpu 字段含义 user: 表示CPU执行用户进程的时间,通常期望用户空间CPU越高越好. sys: 表示CPU在内核运行时间,系统CPU占用率高,表明系统某部分存在瓶颈.通常值越低越好. ...

  3. [bzoj3743 Coci2015] Kamp(树形dp)

    传送门 Description 一颗树n个点,n-1条边,经过每条边都要花费一定的时间,任意两个点都是联通的. 有K个人(分布在K个不同的点)要集中到一个点举行聚会. 聚会结束后需要一辆车从举行聚会的 ...

  4. linux 中配置假域名来测试

    1.linux中配置假域名 找到hosts文件进行编辑 命令:vim /etc/hosts 配置: #centos(本机IP)192.168.1.179 www.imooc.com(假域名,自己设置) ...

  5. linux 编译网卡驱动

    将smsc7500网卡驱动拷贝到/drive/net/usb文件夹下 拷贝ioctl_7500.h  smsc7500usbnet.c smsc7500version.h smsclan7500.h ...

  6. 计算机-award BIOS全教程

  7. BA-siemens-insight报警设置

    以0007001(DDC-B3-09)为例,介绍insight报警的设置方法:

  8. Shell简单介绍

    Shell是一种具备特殊功能的程序.它是介于使用者和linux 操作系统之核心程序(kernel)间的一个接口.为什么我们说 shell 是一种介于系统核心程序与使用者间的中介者呢?读过操作系统概论的 ...

  9. 微信小程序 多图上传解决方案

    为了使代码体积小  我这里将多图上传 封装到单独的一个js 页面的js调用他 我们看firhealth.js文件内容 // pages/home/home.js var upload = requir ...

  10. 在SAE上使用Ueditor的图片上传功能

    SAE上是没有文件夹读写权限的,所以要在SAE使用Ueditor的图片上传功能须要借助SAE的Storage服务. 一.开通Storage服务 在SAE控制台开通Storage服务,并新增一个doma ...