用途

  • 做各种二维三维四维偏序等等。
  • 代替空间巨大的树套树。
  • 数据较弱的时候水分。

思想

我们发现平衡树这种东西功能强大,然而只能做一维上的询问修改,显得美中不足。

于是我们尝试用平衡树的这种二叉树结构,做更高维的事情。

继续沿用平衡树的左儿子比自己小、右儿子比自己大的形态。这时发现,如果小于号定义得不好,那么做高维询问的时候就很难做。

发明者想到了这样一个方法:我们每过一层就划分一次超矩形。

具体地,给每一层一个\(type\),表示这一层是按哪一维切割。切割某一维的时候,拿出中位数,然后分成两边,于是就完成了小于号的定义。

给一张图:

查询的时候,类似线段树,只要完全包含了就返回,否则无脑往左右儿子跑。

如果要动态加入点怎么办?使用替罪羊树的思想,如果太过不平衡就拍扁重构。

时间复杂度分析?建树显然是\(O(n\log n)\)的,插入据说是\(O(n\log^2 n)\),而询问……引用一下AKMer的证明:

实现

以下代码基本没有参考别人的代码,如果有错误请指正。

为了方便,以下均用二维举例子,拓展到高维不会太难。

(其实也是因为我只写过二维)

定义

定义就是最简单的定义。

struct Point{int x,y,w;}p[sz];
int D;
inline bool cmp(const Point &x,const Point &y){return D?x.y<y.y:x.x<y.x;}
const db alpha=0.75;
int ch[sz<<3][2],fa[sz<<3],size[sz<<3],sum[sz<<3],type[sz<<3]; // 数组大小我也不知道要开几倍,反正O(n)的多开一点应该也没事
Point P[sz<<3];
int L[sz<<3][2],R[sz<<3][2]; // 每一维的上下限
#define ls ch[x][0]
#define rs ch[x][1]
int root,cnt;
int st[sz],top;
void erase(int x){st[++top]=x;ls=rs=size[x]=sum[x]=L[x][0]=R[x][0]=L[x][1]=R[x][1]=0;P[x]=(Point){0,0,0};}
int newnode(){return top?st[top--]:++cnt;} // k-d tree经常重构,所以最好垃圾回收

拍扁重构

利用STL中的nth_element函数,可以做到\(O(n\log n)\)建树。

为了切割得较为均匀,这里选择每一维轮换切割。还有另一种方法是切方差最大的一维,但是懒得写了。

Point pp[sz];int m;
int build(int l,int r,int f)
{
if (l>r) return 0;
int x=newnode();fa[x]=f;
type[x]=type[f]^1;
int mid=(l+r)>>1;
D=type[x];nth_element(pp+l,pp+mid,pp+r+1,cmp);
P[x]=pp[mid];
L[x][0]=R[x][0]=P[x].x,L[x][1]=R[x][1]=P[x].y;
ls=build(l,mid-1,x),rs=build(mid+1,r,x);
size[x]=size[ls]+size[rs]+1;sum[x]=sum[ls]+sum[rs]+P[x].w;
rep(i,0,1) if (ch[x][i]) rep(k,0,1) chkmin(L[x][k],L[ch[x][i]][k]),chkmax(R[x][k],R[ch[x][i]][k]);
return x;
}

插入

插入时要判是否平衡,如果不平衡就擦除一整棵子树并重构。

void Erase(int x){if (!x) return;pp[++m]=P[x];Erase(ls),Erase(rs);erase(x);}
void insert(Point p)
{
int top=-1,x=root;
if (!x) return (void)(pp[1]=p,root=build(1,1,0));
while (233)
{
if (max(size[ls],size[rs])>size[x]*alpha&&top==-1) top=x;
++size[x];sum[x]+=p.w;
chkmin(L[x][0],p.x),chkmax(R[x][0],p.x);
chkmin(L[x][1],p.y),chkmax(R[x][1],p.y);
D=type[x];int &y=ch[x][!cmp(p,P[x])];
if (!y)
{
y=newnode();
L[y][0]=R[y][0]=p.x;
L[y][1]=R[y][1]=p.y;
size[y]=1;sum[y]=p.w;type[y]=type[x]^1;fa[y]=x;
P[y]=p;
break;
}
x=y;
}
if (top==-1) return;
m=0;
if (top==root) { Erase(top); root=build(1,m,0); return; }
int f=fa[top],&t=ch[f][ch[f][1]==top];
Erase(top);
t=build(1,m,f);
}

询问

无脑做就好了。

int query(int x,int l0,int r0,int l1,int r1)
{
if (!x) return 0;
if (l0<=L[x][0]&&R[x][0]<=r0&&l1<=L[x][1]&&R[x][1]<=r1) return sum[x];
if (r0<L[x][0]||R[x][0]<l0||r1<L[x][1]||R[x][1]<l1) return 0;
return query(ls,l0,r0,l1,r1)+query(rs,l0,r0,l1,r1)+(l0<=P[x].x&&P[x].x<=r0&&l1<=P[x].y&&P[x].y<=r1?P[x].w:0);
}

例题

LOJ112 三维偏序

LOJ3159「NOI2019」弹跳

目前我也只知道这两个了,毕竟我自己也是刚学qwq

K-D Tree学习笔记的更多相关文章

  1. 珂朵莉树(Chtholly Tree)学习笔记

    珂朵莉树(Chtholly Tree)学习笔记 珂朵莉树原理 其原理在于运用一颗树(set,treap,splay......)其中要求所有元素有序,并且支持基本的操作(删除,添加,查找......) ...

  2. dsu on tree学习笔记

    前言 一次模拟赛的\(T3\):传送门 只会\(O(n^2)\)的我就\(gg\)了,并且对于题解提供的\(\text{dsu on tree}\)的做法一脸懵逼. 看网上的其他大佬写的笔记,我自己画 ...

  3. Link Cut Tree学习笔记

    从这里开始 动态树问题和Link Cut Tree 一些定义 access操作 换根操作 link和cut操作 时间复杂度证明 Link Cut Tree维护链上信息 Link Cut Tree维护子 ...

  4. 矩阵树定理(Matrix Tree)学习笔记

    如果不谈证明,稍微有点线代基础的人都可以在两分钟内学完所有相关内容.. 行列式随便找本线代书看一下基本性质就好了. 学习资源: https://www.cnblogs.com/candy99/p/64 ...

  5. k-d tree 学习笔记

    以下是一些奇怪的链接有兴趣的可以看看: https://blog.sengxian.com/algorithms/k-dimensional-tree http://zgjkt.blog.uoj.ac ...

  6. splay tree 学习笔记

    首先感谢litble的精彩讲解,原文博客: litble的小天地 在学完二叉平衡树后,发现这是只是一个不稳定的垃圾玩意,真正实用的应有Treap.AVL.Splay这样的查找树.于是最近刚学了学了点S ...

  7. dsu on tree 学习笔记

    这是一个黑科技,考虑树链剖分后,每个点只会在轻重链之间转化\(log\)次. 考虑暴力是怎么写的,每次枚举一个点,再暴力把子树全部扫一边. \(dsu\ on\ tree.\)的思想就是保留重儿子不清 ...

  8. kd tree学习笔记 (最近邻域查询)

    https://zhuanlan.zhihu.com/p/22557068 http://blog.csdn.net/zhjchengfeng5/article/details/7855241 KD树 ...

  9. bzoj 1598: [Usaco2008 Mar]牛跑步 [k短路 A*] [学习笔记]

    1598: [Usaco2008 Mar]牛跑步 题意:k短路 ~~貌似A*的题目除了x数码就是k短路~~ \[ f(x) = g(x) + h(x) \] \(g(x)\)为到达当前状态实际代价,\ ...

随机推荐

  1. [BZOJ3681]Arietta(可持久化线段树合并优化建图+网络流)

    暴力建图显然就是S->i连1,i->j'连inf(i为第j个力度能弹出的音符),j'->T连T[j]. 由于是“某棵子树中权值在某区间内的所有点”都向某个力度连边,于是线段树优化建图 ...

  2. winfrom 集成krpano 项目 添加折线

    C#.NET WinFrom开发之嵌入Google浏览器 (CefSharp) 引入静态页面 CefWebBrowser = new ChromiumWebBrowser("http://& ...

  3. axios 发 post 请求,后端接收不到参数的解决方案(转载)

    原文地址:https://www.cnblogs.com/yiyi17/p/9409249.html 问题场景 场景很简单,就是一个正常 axios post 请求: axios({ headers: ...

  4. interface Part2(定义接口)

    一. 在 C# 语言中,类之间的继承关系仅支持单重继承,而接口是为了实现多重继承关系设计的. 二. 一个类能同时实现多个接口,还能在实现接口的同时再继承其他类,并且接口之间也可以继承. 三. 无论是表 ...

  5. vue-cli3.0 关闭eslint校验

    1. 跟着课程学习vue高级训练营时,vue-cli老是报eslint校验错误,把它关了! 网上找到了图中这个写法,可是报错啊! 解决办法:把false改为true   参考:https://blog ...

  6. 3_PHP表达式_5_数据类型转换_类型强制转换

    以下为学习孔祥盛主编的<PHP编程基础与实例教程>(第二版)所做的笔记. PHP类型转换分为类型自动转换和类型强制转换. 3.5.2 类型强制转换 类型强制转换允许编程人员手动将变量的数据 ...

  7. 基于【 责任链模式】二 || 网关zuul过滤器封装

    一.基于责任链模式封装网关拦截 上一篇文章中已经使用建造者模式对网关拦截进行封装,存在一个问题,在连接器build中,每一个拦截都要进行true判断,代码看起来冗余,下面使用责任链模式封装 1.基于责 ...

  8. 1-JavaScript变量

    对于JS的变量这个环节,其实主要要了解一下JS数据类型的存储方法 JS有两种不同的数据类型:基本类型(原始类型),引用类型(对象类型). 1.栈 (stack) 和 堆 (heap) 栈 (stack ...

  9. Java 之 Properties类 属性集

    一.概述 java.util.Properties集合 extends Hashtable<k,v> implements Map<k,v> java.util.Propert ...

  10. iOS 内存管理的一点小问题

    现在大家的项目应该基本都是ARC了,如果还是MRC的话,赶紧转换到ARC吧!最近被临时拉过去开发iPad,由于项目原因,还是使用的MRC.今天在调部分界面的时候,发现一段代码,我怎么看都怎么觉得怪怪的 ...