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. python类的内置attr属性

    class Foo: x=1 def __init__(self,y): self.y=y def __getattr__(self, item): print('----> from geta ...

  2. python 操作jenkins 常用api

    Python-Jenkins 继续寻找,然后我在Jenkins官网上找到了Python-Jenkins API,仔细阅读后发现,它几乎涵盖了大部分Jenkins的操作,大大方便了我们在后台进行对Jen ...

  3. PHP 一句话木马

    eval 函数 eval() 函数把字符串按照 PHP 代码来计算 该字符串必须是合法的 PHP 代码,且必须以分号结尾 如果没有在代码字符串中调用 return 语句,则返回 NULL.如果代码中存 ...

  4. 移植Mplayer到OK6410开发板

    移植Mplayer到OK6410开发板 作者:vasage 项目需要,需要将Mplayer移植到开发板上,所以今天花了一下下午成功移植,其中参考很多文档,后发现许多文档陈旧,些许文档有少量错误,所以这 ...

  5. 2019-04-03 SQL Group By某列,预先对该列进行一个预处理,提炼出共有的信息,即关键字case when 列名什么条件 then 赋值 else 赋值 end as 新列名

    select sum(发行金额) from( select PoolNameFormat,count(cast(ItemValue as decimal(19,4))) as 发行笔数,sum(cas ...

  6. Ubuntu安装Docker 适合Ubuntu17.04版本

    Docker介绍 Docker是一个开源的容器引擎,它有助于更快地交付产品.Docker可将应用程序和基础设施层隔离,并且将基础设施当作程序一样进行管理.使用Docker,可以更快地打包,测试以及部署 ...

  7. nyoj 120 建边构强连通

    #include<stdio.h> #include<string.h> #include<queue> using namespace std; #define ...

  8. 俄罗斯方块c/c++语言代码

    /*******************************/ /******Writer: GJ *******/ /******Language: C *******/ /******Date ...

  9. Unity里包裹Debug,且不影响Debug的重定向

    Debug.Log, Debug.LogWarning, Debug.LogError在project中常常须要再包裹一层.做些定制.也方便开关Log.但有一个问题时.当用一个类将Debug包裹起来后 ...

  10. 【Android 应用开发】 ActionBar 样式具体解释 -- 样式 主题 简单介绍 Actionbar 的 icon logo 标题 菜单样式改动

    作者 : 万境绝尘 (octopus_truth@163.com) 转载请著名出处 : http://blog.csdn.net/shulianghan/article/details/3926916 ...