bzoj 2648: SJY摆棋子 KDtree + 替罪羊式重构
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 + 替罪羊式重构的更多相关文章
- BZOJ 2648: SJY摆棋子 kdtree
2648: SJY摆棋子 题目连接: http://www.lydsy.com/JudgeOnline/problem.php?id=2648 Description 这天,SJY显得无聊.在家自己玩 ...
- bzoj 2648 SJY摆棋子——KDtree
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2648 第一道KDtree! 学习资料:https://blog.csdn.net/zhl30 ...
- BZOJ 2648 SJY摆棋子 ——KD-Tree
[题目分析] KD-Tree第一题,其实大概就是搜索剪枝的思想,在随机数据下可以表现的非常好NlogN,但是特殊数据下会达到N^2. 精髓就在于估价函数get以及按照不同维度顺序划分的思想. [代码] ...
- bzoj 2648: SJY摆棋子&&2716: [Violet 3]天使玩偶 --kdtree
2648: SJY摆棋子&&2716: [Violet 3]天使玩偶 Time Limit: 20 Sec Memory Limit: 128 MB Description 这天,S ...
- BZOJ 2648: SJY摆棋子
2648: SJY摆棋子 Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 2968 Solved: 1011[Submit][Status][Disc ...
- bzoj 2648: SJY摆棋子【KD-tree】
其实理论上cdq更优 核心是依次取x值.y值的mid作为当前节点,向两边递归建立二叉树,树上维护size:子树大小:mx[0/1]:子树内最大x/y:mn[0/1]:子树内最小x/y:d[0/1]:这 ...
- BZOJ 2648: SJY摆棋子(K-D Tree)
Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 6051 Solved: 2113[Submit][Status][Discuss] Descript ...
- bzoj 2648 SJY摆棋子 kd树
题目链接 初始的时候有一些棋子, 然后给两种操作, 一种是往上面放棋子. 另一种是给出一个棋子的位置, 问你离它最近的棋子的曼哈顿距离是多少. 写了指针版本的kd树, 感觉这个版本很好理解. #inc ...
- BZOJ 2648 SJY摆棋子(KD Tree)
http://www.lydsy.com/JudgeOnline/problem.php?id=2648 题意: 思路: KDtree模板题. 参考自http://www.cnblogs.com/ra ...
随机推荐
- 判断list数组里的json对象有无重复,有则去重留1个
查找有无重复的 var personLength = [{ certType: '2015-10-12', certCode:'Apple'}, { certType: '2015-10-12', c ...
- [BZOJ1999] 树网的核 [数据加强版] (树的直径)
传送门 如果只是想验证算法正确性这里是洛谷数据未加强版 Description 设T=(V, E, W) 是一个无圈且连通的无向图(也称为无根树),每条边带有正整数的权,我们称T为树网(treenet ...
- 《代码敲不队》第八次团队作业:Alpha冲刺 第三天
项目 内容 这个作业属于哪个课程 任课教师博客主页链接 这个作业的要求在哪里 作业链接地址 团队名称 代码敲不队 作业学习目标 掌握软件编码实现的工程要求. 团队项目github仓库地址链接 GitH ...
- RobotFrameWork+APPIUM实现对安卓APK的自动化测试----第五篇【AppiumLibrary校验函数介绍】
http://blog.csdn.net/deadgrape/article/details/50619050 以上连作者先跪一下方便面,在上一篇中,作者遗漏了两个常用的函数: 1.长按 Long P ...
- mysql数据库优化原则
一.一个例子 数据库需要处理的行数: 189444*1877*13482~~~479亿 如果在关联字段上加上合适的索引: 数据库需要处理的行数:368006*1*3*1~~~110万 MySQL通常是 ...
- query ajax总是进入error回调函数
query ajax总是进入error回调函数今天纠结了1小时,ajax总是进入了error函数中.平时使用从来没有出现过这种现象,纠结了半小时. 最后稍微总结出了点: 1.以前使用都是服务器端输出S ...
- 数据库连接池和connection的理解
数据库连接池Data Source Pool的理解 1.数据库连接池允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个连接,避免了每个方法里new connection的耗费资源和时间. ...
- C++异常与析构函数及构造函数
析构函数不要抛出异常. 构造函数可以抛出异常,但是要谨慎. 原因下面这篇文章讲的不错,转载如下: http://jarfield.iteye.com/blog/811703 写Java代码的时候,遇到 ...
- 关于C++构造函数一二
关于构造函数的调用顺序: 1.继承关系 2.从属关系 3.static声明的从属关系 关于拷贝构造函数的声明: classname(const classname & rhs) #includ ...
- hdu 4888 2014多校第三场1002 Redraw Beautiful Drawings 网络流
思路:一開始以为是高斯消元什么的.想让队友搞,结果队友说不好搞,可能是网络流.我恍然,思路立刻就有了. 我们建一个二部图.左边是行,右边是列,建个源点与行建边,容量是该行的和.列与新建的汇点建边.容量 ...