首页 > 其他分享 >K-D Tree 学习笔记

K-D Tree 学习笔记

时间:2024-12-27 10:30:53浏览次数:7  
标签:rs int Tree 笔记 学习 re ls KDT id

注:\(K-D\ Tree\) 的应用中由于大量用到了 \(dfs\) 剪枝,所以通常不是正解。但是由于他相当好写,而且通常跑的不慢,所以也广为流传。感觉像是一种半骗分思路。下文简称其为 \(KDT\)。


一、\(K-D\ Tree\)

我们都知道 \(2D,3D\) 表示二维、三维,所以 \(KDT\) 也很好理解,就是 \(K\) 维的情况下建的树。

他的基本建树思路就是交替枚举坐标,每次取当前坐标 \(k\) 的中位数,将点集分成两个部分,继续建树。为了方便建树,我们可以使用 \(nth\_element\) 这个 \(STL\)。当然,此时的数组中点就是该树的根,记录自己的位置和这个 \(K\) 维矩形。

在插入时有两种思路(下文询问表示矩阵求和之类的,不是平面最近点对一类):

  1. 仿照替罪羊树,在树不平衡到一定程度时暴力拍平重构,单次修改时间复杂度均摊是 \(O(\sqrt{n\log n})\),单次询问时间复杂度均摊是 \(O(\sqrt{n\log n}+n^{1-\frac 1k})\)。

  2. 采用二进制分组的方式,建立 \(\log n\) 棵 \(KDT\),第 \(i\) 棵大小为 \(2^i\)(编号从 \(0\) 开始),每次加点时,从 \(0\) 号树开始合并,直到出现空位,再将新的树放进去。查询遍历所有树即可。单次修改时间复杂度均摊为 \(O(\log^2n)\),单次询问时间复杂度均摊是 \(O(n^{1-\frac 1k})\)。

我采用的是第二种方法。

二、平面最近最远点对

经典问题了。

你不会以为 \(KDT\) 有什么精妙绝伦的解法吧?

实际上此时 \(KDT\) 只能 \(dfs\) 求解。但是结合 \(A^*\) 与一个信竞生多年的 \(dfs\) 剪枝经验,我们可以发现两个优化:

  1. 假如将他插入 \(KDT\) 中,他在哪个子树,哪个子树就更有可能取到最小值。

  2. 假如我们走这棵子树,就算走到最近/远处也不优于当前答案,那么我们就不需要走这棵子树。这个判断可以使用估价函数。

那么我们就可以相对快速的求解了。

//SDOI2010 捉迷藏
#include<bits/stdc++.h>
#define ls(x) nd[x].ls
#define rs(x) nd[x].rs
#define id(x,y) nd[x].id[y]
#define lp(x,y) nd[x].lp[y]
#define rd(x,y) nd[x].rd[y]
using namespace std;
const int N=1e5+5;
int n,ans=2e9;
namespace kd_tree{
	int rt[25],a[N],tot,kw;
	struct node{
		int ls,rs,id[2];
		int lp[2],rd[2];
	}nd[N];int tp,m;
	int cmp(int x,int y){
		return id(x,kw)<id(y,kw);
	}int dis(int x,int y){
		return abs(id(x,0)-id(y,0))+abs(id(x,1)-id(y,1));
	}int rec1(int x,int y){
		int re=max(id(y,0)-rd(x,0),0)+max(lp(x,0)-id(y,0),0);
		return re+max(id(y,1)-rd(x,1),0)+max(lp(x,1)-id(y,1),0);
	}int rec2(int x,int y){
		int re=max(abs(id(y,0)-rd(x,0)),abs(id(y,0)-lp(x,0)));
		return re+max(abs(id(y,1)-rd(x,1)),abs(id(y,1)-lp(x,1)));
	}void push_up(int x){
		lp(x,0)=min({id(x,0),lp(ls(x),0),lp(rs(x),0)});
		lp(x,1)=min({id(x,1),lp(ls(x),1),lp(rs(x),1)});
		rd(x,0)=max({id(x,0),rd(ls(x),0),rd(rs(x),0)});
		rd(x,1)=max({id(x,1),rd(ls(x),1),rd(rs(x),1)});
	}int build(int l,int r,int k){
		int mid=(l+r)/2;kw=k;
		nth_element(a+l,a+mid,a+r+1,cmp);
		if(l<mid) ls(a[mid])=build(l,mid-1,k^1);
		if(r>mid) rs(a[mid])=build(mid+1,r,k^1);
		return push_up(a[mid]),a[mid];
	}void clear(int &x){
		a[++tp]=x;
		if(ls(x)) clear(ls(x));
		if(rs(x)) clear(rs(x));x=0;
	}void add(int x){
		a[tp=1]=x;int t=0;
		while(rt[t]) clear(rt[t]),t++;
		rt[t]=build(1,tp,0);
	}void insert(int x,int y){
		id(++m,0)=x,id(m,1)=y,add(m);
	}void que1(int x,int y,int k,int &re){
		if(x!=y) re=min(re,dis(x,y));
		if(id(y,k)<id(x,k)){
			if(ls(x)&&rec1(ls(x),y)<re) que1(ls(x),y,k^1,re);
			if(rs(x)&&rec1(rs(x),y)<re) que1(rs(x),y,k^1,re);
		}else{
			if(rs(x)&&rec1(rs(x),y)<re) que1(rs(x),y,k^1,re);
			if(ls(x)&&rec1(ls(x),y)<re) que1(ls(x),y,k^1,re);
		}
	}void que2(int x,int y,int k,int &re){
		if(x!=y) re=max(re,dis(x,y));
		if(id(y,k)>id(x,k)){
			if(ls(x)&&rec2(ls(x),y)>re) que2(ls(x),y,k^1,re);
			if(rs(x)&&rec2(rs(x),y)>re) que2(rs(x),y,k^1,re);
		}else{
			if(rs(x)&&rec2(rs(x),y)>re) que2(rs(x),y,k^1,re);
			if(ls(x)&&rec2(ls(x),y)>re) que2(ls(x),y,k^1,re);
		}
	}int qu1(int ij){
		int re=2e9,t=0;
		while(t<25){if(rt[t]) que1(rt[t],ij,0,re);t++;}
		return re;
	}int qu2(int ij){
		int re=0,t=0;
		while(t<25){if(rt[t]) que2(rt[t],ij,0,re);t++;}
		return re;
	}
}using namespace kd_tree;
int main(){
	ios::sync_with_stdio(0);
	cin.tie(0),cout.tie(0);
	cin>>n,lp(0,0)=lp(0,1)=2e9;
	for(int i=1,x,y;i<=n;i++)
		cin>>x>>y,insert(x,y);
	for(int i=1;i<=n;i++)
		ans=min(ans,qu2(i)-qu1(i));
	return cout<<ans,0;
}

标签:rs,int,Tree,笔记,学习,re,ls,KDT,id
From: https://www.cnblogs.com/chang-an-22-lyh/p/18634952/kd_tree-zj

相关文章

  • 《LLM入门教程》大模型教程笔记5:一、面向开发者的提示工程——2. 提示原则——原则二:
    项目地址:llm-cookbook教程在线阅读:面向开发者的LLM入门教程openAIPython库版本:1.52.1文章目录第二章提示原则二、原则二给模型时间去思考2.1指定完成任务所需的步骤复杂任务需求代码示例(原)代码示例(基于原代码修改)存在问题改进prompt(进一步告知大模型需要的输出格......
  • 2024-2025-1 20241316 《计算机基础与程序设计》第十四周学习总结
    2024-2025-120241316《计算机基础与程序设计》第十四周学习总结作业信息这个作业属于哪个课程2024-2025-1-计算机基础与程序设计这个作业要求在哪里2024-2025-1计算机基础与程序设计第十四周作业这个作业的目标《C语言程序设计》第13-14章并完成云班课测试作......
  • 计算机毕业设计hadoop+spark+hive薪资预测 招聘推荐系统 招聘可视化大屏 招聘爬虫 Pyt
    温馨提示:文末有CSDN平台官方提供的学长联系方式的名片!温馨提示:文末有CSDN平台官方提供的学长联系方式的名片!温馨提示:文末有CSDN平台官方提供的学长联系方式的名片!作者简介:Java领域优质创作者、CSDN博客专家、CSDN内容合伙人、掘金特邀作者、阿里云博客专家、51CTO......
  • 你学习javascript的路线是怎样的?
    学习JavaScript(特别是针对前端开发)的路线可以因人而异,但以下是一个建议的学习路径,帮助你从基础到进阶,再到深入掌握JavaScript和前端开发技术:阶段一:基础学习JavaScript基础语法:变量、数据类型(Number,String,Boolean,Object,Null,Undefined等)运算符(算术、比较、逻辑、位......
  • 学习HTML你有哪些心得?
    学习HTML对于前端开发来说是非常基础且重要的一步。以下是我在学习HTML过程中的一些心得和体会:理解基础语法:HTML的语法相对简单,主要由标签(tags)构成。理解如何正确地使用标签,包括开标签、闭标签以及自闭合标签,是编写有效HTML代码的关键。同时,掌握HTML文档的基本结构,如<!DOCTYPEh......
  • GO 学习笔记之三 基础语法(5) 切片
    一、定义Go数组的长度不可改变,在特定场景中这样的集合就不太适用,Go中提供了一种灵活,功能强悍的内置类型切片("动态数组"),与数组相比切片的长度是不固定的,可以追加元素,在追加时可能使切片的容量增大。其存在容量和长度的说法,长度是实际数据的长度,容量是可容纳的数组长度。容量......
  • NLP论文速读(AAAI 2024)|面向序列生成的基于高效采样强化学习 (Efficient Sampling-ba
    论文速读|ESRL:EfficientSampling-basedReinforcementLearning forSequenceGeneration论文信息:简介:   本文探讨了将强化学习(ReinforcementLearning,RL)应用于序列生成模型的背景。序列生成是一个长期决策问题,而RL特别适合优化长期奖励,例如序列级别的评分......
  • GTM148学习(抄书)笔记 [不定期更新]
    ContentsContentsChapterI.GroupsandHomomorphismsPermutationsCyclesFactorizationintoDisjointCyclesEvenandOddPermutationsSemigroupsGroupsHomomorphismsChapterI.GroupsandHomomorphismsPermutationsDefinition1.1.1If\(X\)isan......
  • 渣录笔记1《Learning the vi & Vim Editors》
    先说为什么要阅读这本书。著名的Vim之父BramMoolenaar(BramMoolenaar'swebsite-home)主页上面有他公开推荐的Vim书籍,详情见链接:Vim之父主页的Vim书籍(http://iccf-holland.org/vim_books.html),斯人已逝,聊作纪念。个人就在国内某宝上买了一本来看看,(52.2元),先从第一本看,贪......
  • 《计算机组成及汇编语言原理》阅读笔记:p116-p120
    《计算机组成及汇编语言原理》学习第7天,p116-p120总结,总计5页。一、技术总结1.CPU优化(1)increaseoverallperformancenumber例如:16位电脑提升到32位电脑。(2)multiprocessingOnewaytomakecomputersmoreusefulistoallowthemtorunmorethanoneprogram......