BZOJ - 2648 KD树 最近点查询
省赛后躺尸几天又回来更新了,内容是说好的KD树..
具体操作从代码中感受一下
感觉已经把KD树尽量封装好了(虽然全局的D看着极不顺眼)
需要注意的是估值函数的判断条件
#include<bits/stdc++.h>
#define rep(i,j,k) for(register int i=j;i<=k;i++)
#define rrep(i,j,k) for(register int i=j;i>=k;i--)
#define erep(i,u) for(register int i=head[u];~i;i=nxt[i])
#define print(a) printf("%lld",(ll)(a))
#define println(a) printf("%lld\n",(ll)(a))
#define printbk(a) printf("%lld ",(ll)(a))
using namespace std;
const int MAXN = 1e6+11;
const int INF = 0x7fffffff;
typedef long long ll;
ll read(){
ll x=0,f=1;register char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int D;
struct point{
int x[2];
bool operator < (const point &rhs) const{
return x[D]<rhs.x[D];
}
};
struct KD{
int son[MAXN][2];
point p[MAXN],mn[MAXN],mx[MAXN];
int root,ans,tot;
void init(){
ans=INF; tot=D=0;
}
void pu(int o){
rep(i,0,1){
if(son[o][i]) rep(j,0,1){
mn[o].x[j]=min(mn[o].x[j],mn[son[o][i]].x[j]);
mx[o].x[j]=max(mx[o].x[j],mx[son[o][i]].x[j]);
}
}
}
int build(int now,int l,int r){
int mid=l+r>>1;
tot++; son[mid][0]=son[mid][1]=0;
D=now;nth_element(p+l,p+mid,p+r+1);//[l,r+1)
mn[mid].x[0]=mx[mid].x[0]=p[mid].x[0];
mn[mid].x[1]=mx[mid].x[1]=p[mid].x[1];
if(l<mid) son[mid][0]=build(now^1,l,mid-1);
if(r>mid) son[mid][1]=build(now^1,mid+1,r);
pu(mid);
return mid;
}
void insert(int &o,int now,point v){
if(!o){
o=++tot;
p[o].x[0]=mn[o].x[0]=mx[o].x[0]=v.x[0];
p[o].x[1]=mn[o].x[1]=mx[o].x[1]=v.x[1];
}else{
insert(son[o][p[o].x[now]<v.x[now]],now^1,v);
pu(o);
}
}
inline int dis(point &a,point &b){
return abs(a.x[0]-b.x[0])+abs(a.x[1]-b.x[1]);
}
inline int eva(int o,point &v){
int res=0;
rep(i,0,1) if(v.x[i]<mn[o].x[i]||v.x[i]>mx[o].x[i]){
res+=min(abs(v.x[i]-mn[o].x[i]),abs(v.x[i]-mx[o].x[i]));
}
return res;
}
void query(int o,point v){
if(!o) return;
int d1=dis(p[o],v),d2=INF,d3=INF;
if(d1<ans) ans=d1;
if(son[o][0]) d2=eva(son[o][0],v);
if(son[o][1]) d3=eva(son[o][1],v);
if(d2<d3){
if(d2<ans) query(son[o][0],v);
if(d3<ans) query(son[o][1],v);
}else{
if(d3<ans) query(son[o][1],v);
if(d2<ans) query(son[o][0],v);
}
}
inline int query(point v){
ans=INF;
query(root,v);
return ans;
}
}kd;
int main(){
int n,m;
while(cin>>n>>m){
kd.init();
rep(i,1,n){
kd.p[i].x[0]=read();
kd.p[i].x[1]=read();
}
kd.root=kd.build(0,1,n);
rep(i,1,m){
int op=read();
point tmp;
tmp.x[0]=read();
tmp.x[1]=read();
if(op==1){
kd.insert(kd.root,0,tmp);
}else{
println(kd.query(tmp));
}
}
}
return 0;
}
Update:发现kd树的复杂度常数非常大,所以把max/min之类的改为手动判断能快相当多
#include<bits/stdc++.h>
#define rep(i,j,k) for(register int i=j;i<=k;i++)
#define rrep(i,j,k) for(register int i=j;i>=k;i--)
#define erep(i,u) for(register int i=head[u];~i;i=nxt[i])
#define print(a) printf("%lld",(ll)(a))
#define println(a) printf("%lld\n",(ll)(a))
#define printbk(a) printf("%lld ",(ll)(a))
using namespace std;
const int MAXN = 1e6+11;
const int INF = 0x7fffffff;
typedef long long ll;
ll read(){
ll x=0,f=1;register char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int D;
struct point{
int x[2];
bool operator < (const point &rhs) const{
return x[D]<rhs.x[D];
}
};
struct KD{
int son[MAXN][2];
point p[MAXN],mn[MAXN],mx[MAXN];
int root,ans,tot;
void init(){
ans=INF; tot=D=0;
}
void pu(int o){
rep(i,0,1){
if(son[o][i]) rep(j,0,1){
if(mn[son[o][i]].x[j]<mn[o].x[j]) mn[o].x[j]=mn[son[o][i]].x[j];
if(mx[son[o][i]].x[j]>mx[o].x[j]) mx[o].x[j]=mx[son[o][i]].x[j];
}
}
}
int build(int now,int l,int r){
int mid=l+r>>1;
tot++; son[mid][0]=son[mid][1]=0;
D=now;nth_element(p+l,p+mid,p+r+1);//[l,r+1)
mn[mid].x[0]=mx[mid].x[0]=p[mid].x[0];
mn[mid].x[1]=mx[mid].x[1]=p[mid].x[1];
if(l<mid) son[mid][0]=build(now^1,l,mid-1);
if(r>mid) son[mid][1]=build(now^1,mid+1,r);
pu(mid);
return mid;
}
void insert(int &o,int now,point v){
if(!o){
o=++tot;
p[o].x[0]=mn[o].x[0]=mx[o].x[0]=v.x[0];
p[o].x[1]=mn[o].x[1]=mx[o].x[1]=v.x[1];
}else{
insert(son[o][p[o].x[now]<v.x[now]],now^1,v);
pu(o);
}
}
inline int dis(point &a,point &b){
return abs(a.x[0]-b.x[0])+abs(a.x[1]-b.x[1]);
}
inline int eva(int o,point &v){
int res=0;
rep(i,0,1) if(v.x[i]<mn[o].x[i]||v.x[i]>mx[o].x[i]){
if(v.x[i]<mn[o].x[i]) res+=mn[o].x[i]-v.x[i];
else res+=v.x[i]-mx[o].x[i];
}
return res;
}
void query(int o,point v){
if(!o) return;
int d1=dis(p[o],v),d2=INF,d3=INF;
if(d1<ans) ans=d1;
if(son[o][0]) d2=eva(son[o][0],v);
if(son[o][1]) d3=eva(son[o][1],v);
if(d2<d3){
if(d2<ans) query(son[o][0],v);
if(d3<ans) query(son[o][1],v);
}else{
if(d3<ans) query(son[o][1],v);
if(d2<ans) query(son[o][0],v);
}
}
inline int query(point v){
ans=INF;
query(root,v);
return ans;
}
}kd;
int main(){
int n,m;
while(cin>>n>>m){
kd.init();
rep(i,1,n){
kd.p[i].x[0]=read();
kd.p[i].x[1]=read();
}
kd.root=kd.build(0,1,n);
rep(i,1,m){
int op=read();
point tmp;
tmp.x[0]=read();
tmp.x[1]=read();
if(op==1){
kd.insert(kd.root,0,tmp);
}else{
println(kd.query(tmp));
}
}
}
return 0;
}
BZOJ - 2648 KD树 最近点查询的更多相关文章
- BZOJ - 4066 KD树 范围计数 暴力重构
题意:单点更新,大矩阵(\(n*n,n≤10^5\))求和 二维的KD树能使最坏情况不高于\(O(N\sqrt{N})\) 核心在于query时判断当前子树维护的区间是否有交集/当前子节点是否在块中, ...
- BZOJ - 3489 KD树 范围计数 空间思维转换
题意:给定数列\(a[1...n]\),\(Q\)次查询\([L,R]\)中只出现一次的最大值 这道题的做法比较劲.. 对每个元素构造三维空间的点\((i,pre[i],next[i])\),查询\( ...
- BZOJ - 1941 Hide and Seek (kd树)
题目链接 kd树模板题,求二维空间上的最远点/最近点. 对所有点建立kd树,分别查询每个点即可.单次查询期望时间复杂度$O(logn)$ #include<bits/stdc++.h> u ...
- 统计学习方法学习(四)--KNN及kd树的java实现
K近邻法 1基本概念 K近邻法,是一种基本分类和回归规则.根据已有的训练数据集(含有标签),对于新的实例,根据其最近的k个近邻的类别,通过多数表决的方式进行预测. 2模型相关 2.1 距离的度量方式 ...
- bzoj 2648 SJY摆棋子 kd树
题目链接 初始的时候有一些棋子, 然后给两种操作, 一种是往上面放棋子. 另一种是给出一个棋子的位置, 问你离它最近的棋子的曼哈顿距离是多少. 写了指针版本的kd树, 感觉这个版本很好理解. #inc ...
- C# 通过KD树进行距离最近点的查找.
本文首先介绍Kd-Tree的构造方法,然后介绍Kd-Tree的搜索流程及代码实现,最后给出本人利用C#语言实现的二维KD树代码.这也是我自己动手实现的第一个树形的数据结构.理解上难免会有偏差,敬请各位 ...
- kd树解平面最近点对
早上起来头有点疼,突然就想到能不能用kd树解平面最近点对问题,就找了道题试了一下,结果可以,虽然效率不高,但还是AC了~ 题目链接:http://acm.hdu.edu.cn/showproblem. ...
- bzoj 3489: A simple rmq problem k-d树思想大暴力
3489: A simple rmq problem Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 551 Solved: 170[Submit][ ...
- bzoj 3053 HDU 4347 : The Closest M Points kd树
bzoj 3053 HDU 4347 : The Closest M Points kd树 题目大意:求k维空间内某点的前k近的点. 就是一般的kd树,根据实测发现,kd树的两种建树方式,即按照方差 ...
随机推荐
- Tensorflow训练结果测试
代码参考(https://blog.csdn.net/disiwei1012/article/details/79928679) import osimport sysimport randomimp ...
- Django框架 之 form组件的钩子
Django框架 之 form组件的钩子 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 3 ...
- Codeforces 429B B. Working out
题目意思: 给n*m的矩阵,每个格子有个数,A从(1,1)出发只能向下或右走,终点为(n,m),B从(n,1)出发只能向上或右走,终点为(1,m).两个人的速度不一样,走到的格子可以获的该格子的数,两 ...
- LightOJ 1065 Island of Survival (概率DP?)
题意:有 t 只老虎,d只鹿,还有一个人,每天都要有两个生物碰面,1.老虎和老虎碰面,两只老虎就会同归于尽 2.老虎和人碰面或者和鹿碰面,老虎都会吃掉对方 3.人和鹿碰面,人可以选择杀或者不杀该鹿4. ...
- Eclipse中连接数据库错误:com.microsoft.sqlserver.jdbc.SQLServerException: 之类的错误
原创 错误:org.apache.jasper.JasperException: Unable to compile class for JSP 原因是页面指令中 import="java. ...
- 异步 Action 的定义
ASP.NET MVC 3中的异步 Action 通过两个匹配的方法XxxAsync/XxxCompleted 来定义,这样的异步 Action 只能定义在继承自 AsyncConoller 的类型中 ...
- 前端框架 json 返回值
layui: string strJson = "{\"code\": \"0\",\"msg\": \"\" ...
- $(this)在ajax里面不生效的探究
第一个箭头时, 如果没有将$(this) 赋值给 _this ,那么$(this)就无法在ajax方法里面使用. 应该是应为他们属于不同的域. 赋值给_this的话, 就类似于全局变量
- C#中的枚举使用
基本用法 默认从0开始分配各个枚举值对应的数字值 public enum VariableType { Type1, Type2 } 指定各个枚举值对应的数字值 public enum Variabl ...
- WebStrom常用快捷键
查找替换 ctrl+shift+N 通过文件名快速查找工程内的文件(必记) ctrl+shift+alt+N 通过一个字符快速查找位置(必记) ctrl+F 在文件内快速查找代码 ctrl+R ...