模板:K-D tree

文章目录

  • 前言
  • 思想
  • 能解决的问题
  • 操作
    • 建树
    • 询问
    • 修改
  • 完整代码

所谓KDtree,就是有K个D的树

(逃)

前言

KDtree是一种解决多维问题的暴力数据结构
K维状态下的最差复杂度是nk−1/kn^{k-1/k}nk1/k
在最常见的2Dtree中就是根号n
但是玄学的它常常能到logn的复杂度
是骗分利器 (据说)
代码实现很恶心,又长又长
和splay有一拼
甚至更加恶心

思想

按照每一维交错排序
不断用超平面尽量的平分所有点

能解决的问题

通常是一些数据为二元组,对满足某些偏序关系的数据进行操作的问题
或者是各种经典的二维平面第k近第k远之类的

操作

建树

就是按照思想所说的模拟即可
使用O(n)的nth_element十分方便

int build(int l,int r,int f){int mid=(l+r)>>1;F=f;nth_element(p+l,p+mid,p+r+1);int k=New(p[mid]);if(l<mid) tr[k].ls=build(l,mid-1,f^1);if(mid<r) tr[k].rs=build(mid+1,r,f^1);pushup(k);return k;
}

询问

经典的KD树的询问就是寻找最近点
递归到一个结点时
首先用该点更新答案
然后算出两个子树的点范围围成的矩形到改点的最小值
计算的trick:

int getdis(point o,int k){int res=0;for(int i=0;i<=1;i++){res+= max(0,tr[k].mn[i]-o.x[i])+max(0,o.x[i]-tr[k].mx[i]);}return res;
}

然后如果某个子树的距离最小值比当前答案大,可以直接跳过
否则先从最小值较小的开始尝试搜索
代码如下:

void query(int k,point now){int dl,dr,l=tr[k].ls,r=tr[k].rs;ans=min(ans,dis(tr[k].o,now));if(l) dl=getdis(now,tr[k].ls);if(r) dr=getdis(now,tr[k].rs);if(dl<dr){if(l&&dl<ans) query(tr[k].ls,now);if(r&&dr<ans) query(tr[k].rs,now);}else{if(r&&dr<ans) query(tr[k].rs,now);if(l&&dl<ans) query(tr[k].ls,now);}
}

当然,我们还要维护每个结点的子树中的点的矩形的范围:

void pushup(int k){int l=tr[k].ls,r=tr[k].rs;for(int i=0;i<=1;i++){tr[k].mn[i]=tr[k].mx[i]=tr[k].o.x[i];if(l){tr[k].mn[i]=min(tr[k].mn[i],tr[l].mn[i]);tr[k].mx[i]=max(tr[k].mx[i],tr[l].mx[i]);}if(r){tr[k].mn[i]=min(tr[k].mn[i],tr[r].mn[i]);tr[k].mx[i]=max(tr[k].mx[i],tr[r].mx[i]);}}tr[k].siz=tr[l].siz+tr[r].siz+1;return;
}

修改

考虑直接顺着树的性质往下递归到空子树建个新点即可:

void insert(int &k,int f,point u){if(!k){k=New(u);return;}if(u.x[f]<=tr[k].o.x[f]) insert(tr[k].ls,f^1,u);else insert(tr[k].rs,f^1,u);pushup(k);check(k,f);return;
}

代码中的那个check是干啥的?
这样在插入点规模过大时会使树失衡,变成O(n)
所以我们仿照替罪羊树的思路,设定常数x如果某个结点的一个子树的大小超过总大小x倍,把整个子树拍扁再重构
所谓“拍扁”,就是把所有点结点放回一维数组中:

void pia(int k,int num){if(tr[k].ls) pia(tr[k].ls,num);p[num+tr[tr[k].ls].siz+1]=tr[k].o;if(tr[k].rs) pia(tr[k].rs,num+tr[tr[k].ls].siz+1);rub[++top]=k;return;
}

(rub数组用于回收废点)
然后重构直接调用build就行了:

void check(int &k,int f){if(tr[tr[k].ls].siz>tr[k].siz*A||tr[tr[k].rs].siz>tr[k].siz*A){pia(k,0);k=build(1,tr[k].siz,f);//printf("ok");}return;
}

完整代码

题目传送门

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=2e6+100;
const int M=1050;
const int mod=998244353;
inline ll read(){ll x=0,f=1;char c=getchar();while(!isdigit(c)){if(c=='-') f=-1;c=getchar();}while(isdigit(c)){x=x*10+c-'0';c=getchar();}return x*f;
}
int n,m,tot,num;
int rub[N],top;
int F;
struct point{int x[2];}p[N];
#define dis(a,b) (abs(a.x[0]-b.x[0])+abs(a.x[1]-b.x[1]))
bool operator < (const point a,point b){return a.x[F]<b.x[F];}
struct node{int mn[2],mx[2],ls,rs,siz;point o;
}tr[N];
int New(point u){int x=top?rub[top--]:++tot;tr[x].o=u;tr[x].siz=1;tr[x].mn[0]=tr[x].mx[0]=u.x[0];tr[x].mn[1]=tr[x].mx[1]=u.x[1];tr[x].ls=tr[x].rs=0;return x;
}
void pushup(int k){int l=tr[k].ls,r=tr[k].rs;for(int i=0;i<=1;i++){tr[k].mn[i]=tr[k].mx[i]=tr[k].o.x[i];if(l){tr[k].mn[i]=min(tr[k].mn[i],tr[l].mn[i]);tr[k].mx[i]=max(tr[k].mx[i],tr[l].mx[i]);}if(r){tr[k].mn[i]=min(tr[k].mn[i],tr[r].mn[i]);tr[k].mx[i]=max(tr[k].mx[i],tr[r].mx[i]);}}tr[k].siz=tr[l].siz+tr[r].siz+1;return;
}
void print(int k){printf("k=%d (%d %d) ls=%d rs=%d mn=(%d %d) mx=(%d %d)\n",k,tr[k].o.x[0],tr[k].o.x[1],tr[k].ls,tr[k].rs,tr[k].mn[0],tr[k].mn[1],tr[k].mx[0],tr[k].mx[1]);
}
int build(int l,int r,int f){int mid=(l+r)>>1;F=f;nth_element(p+l,p+mid,p+r+1);int k=New(p[mid]);if(l<mid) tr[k].ls=build(l,mid-1,f^1);if(mid<r) tr[k].rs=build(mid+1,r,f^1);pushup(k);return k;
}
void pia(int k,int num){if(tr[k].ls) pia(tr[k].ls,num);p[num+tr[tr[k].ls].siz+1]=tr[k].o;if(tr[k].rs) pia(tr[k].rs,num+tr[tr[k].ls].siz+1);rub[++top]=k;return;
}
double A=0.75;
void check(int &k,int f){if(tr[tr[k].ls].siz>tr[k].siz*A||tr[tr[k].rs].siz>tr[k].siz*A){pia(k,0);k=build(1,tr[k].siz,f);//printf("ok");}return;
}
void insert(int &k,int f,point u){if(!k){k=New(u);return;}if(u.x[f]<=tr[k].o.x[f]) insert(tr[k].ls,f^1,u);else insert(tr[k].rs,f^1,u);pushup(k);check(k,f);return;
}
int getdis(point o,int k){int res=0;for(int i=0;i<=1;i++){res+= max(0,tr[k].mn[i]-o.x[i])+max(0,o.x[i]-tr[k].mx[i]);}return res;
}
int ans;
void query(int k,point now){int dl,dr,l=tr[k].ls,r=tr[k].rs;ans=min(ans,dis(tr[k].o,now));if(l) dl=getdis(now,tr[k].ls);if(r) dr=getdis(now,tr[k].rs);if(dl<dr){if(l&&dl<ans) query(tr[k].ls,now);if(r&&dr<ans) query(tr[k].rs,now);}else{if(r&&dr<ans) query(tr[k].rs,now);if(l&&dl<ans) query(tr[k].ls,now);}
}
int r;
int main(){
//	freopen("a.in","r",stdin);
//	freopen("a.out","w",stdout);n=read();m=read();for(int i=1;i<=n;i++){p[i]=(point){read(),read()};}r=build(1,n,0);for(int i=1;i<=m;i++){int op=read(),x=read(),y=read();point o=(point){x,y};if(op==1){insert(r,0,o);}else{ans=2e9;query(r,o);printf("%d\n",ans);}}return 0;
}
/**/

thanks for reading!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/317923.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

AT3877-[ARC089C]GraphXY【构造】

正题 题目链接:https://www.luogu.com.cn/problem/AT3877 题目大意 给出一个大小为ABA\times BAB的矩阵ddd 要求构造一个点数不超过300300300的有向图满足 图中没有重边和自环图中的边权为[0,100][0,100][0,100]的整数或者未知数X/YX/YX/Y对于所有X∈[1,A],Y∈[1,B]X\in[1,A…

领域驱动设计,让程序员心中有码(六)

领域驱动设计-聚合&#xff0c;一种极简的思维模式引言作为IT技术产业飞速发展的产物&#xff0c;软件工程学已经成为当今时代非常重要的一个学科。作为一名资深的软件开发从业者&#xff0c;我们需要学习的东西实际上已经远远超出了原本在大学教育阶段所接受的知识深度和广度&…

CF856D Masha and Cactus(树上 DP+抵消贡献技巧)

CF856D Masha and Cactus 我们先捞出一个根节点&#xff0c;那么一次旋变就是对路径上点的覆盖。 设 \(dp_{i,0}\) 表示 \(i\) 没有选择时子树内最大收益&#xff0c;\(dp_{i,1}\) 表示 \(i\) 选择时子树内最大收益&#xff0c;那么将每条边存在 \(lca\) 上。 之后贡献怎么算&a…

hdu 5094 Maze

题意&#xff1a; n*m大的迷宫 &#xff0c;有p种钥匙。钥匙最多有10种。 然后一个k&#xff0c;然后k行表示 (x1,y1),(x2,y2)直接有门或者墙。 如果g0 &#xff0c;就是有墙&#xff0c; 如果g>0 表示有门&#xff0c;且门需要第g把钥匙才能开。 然后下来一个s&#xff…

数论分块练习([CF830 C]Bamboo Partition + [hdu 6395]Sequence )

文章目录T1&#xff1a;SequencetitlesolutionT2&#xff1a;Bamboo PartitiontitlesolutioncodeT1&#xff1a;Sequence title 传送 solution 一眼就是很裸的矩阵加速 ⌊pl⌋\lfloor\frac{p}{l}\rfloor⌊lp​⌋分块矩阵加速就可以了 [BA1][DC⌊pl⌋010001]\begin{bmatrix}…

YBTOJ:染颜色(KDtree)

文章目录题目描述数据范围解析代码题目描述 数据范围 n≤105,T≤5n\le10^5,T\le5n≤105,T≤5 解析 关键是对问题的转化 考虑一次修改&#xff0c;一个点需要满足哪些条件才可以满足 1.与x的距离不超过lll 2.在x的子树内 这两个条件可以转化为对深度的限制和对dfs序的限制 这样…

Kubernetes初探[1]:部署你的第一个ASP.NET Core应用到k8s集群

Kubernetes简介Kubernetes是Google基于Borg开源的容器编排调度引擎&#xff0c;作为CNCF&#xff08;Cloud Native Computing Foundation&#xff09;最重要的组件之一&#xff0c;它的目标不仅仅是一个编排系统&#xff0c;而是提供一个规范&#xff0c;可以让你来描述集群的架…

P5933 [清华集训2012]串珠子(连通性 状压 计数)

P5933 [清华集训2012]串珠子 \(\color{yellow}{\bigstar\texttt{Trick}}\)&#xff1a;遇到连通性题可以暂时忽略是否联通。 设 \(g_s\) 表示集合为 \(s\) 的点的子图有多少个&#xff0c;可以不连通&#xff1b;\(f_s\) 表示答案。 那么 \(g_s\) 可以直接计算 \(g_s\prod_{(i&…

AT2365-[AGC012E]Camel and Oases【状压dp】

正题 题目链接:https://www.luogu.com.cn/problem/AT2365 题目大意 一个数轴上有nnn个点&#xff0c;开始你有个水壶容量为VVV&#xff0c;你每次有两个操作 走到一个距离与你不超过VVV的点让V⌊V2⌋V\lfloor\frac V2\rfloorV⌊2V​⌋&#xff0c;然后跳到任意一个点。 对于…

01分数规划

参考文章 01分数规划 什么是01分数规划&#xff1a; 给定n个a[i]和b[i]&#xff0c;a[i]和b[i]绑定在一起要选同时选&#xff0c;求sum(a[i]) 除以 sum(b[i]) 的最大值&#xff0c;sum为求和函数 对于这种问题我们可以多定义一个数组x[1…n]&#xff0c;x为bool型只取0或者1,…

CF1156D 0-1-Tree(换根DP)

牛犇犇titlesolutioncodetitle 戳一戳 solution 直接设dp[i][k]dp[i][k]dp[i][k]表示以iii为根时&#xff0c;子树内&#xff0c;边权为kkk时的答案 &#xff08;定义写得好复杂&#xff0c;可略过&#xff09; 考虑对于点uuu&#xff0c;vvv是他的一个儿子&#xff0c;两点…

模版:替罪羊树

文章目录前言注意事项代码所谓替罪羊树&#xff0c;就是有一头替罪羊的树 &#xff08;逃&#xff09; 前言 在看完了一大堆各种平衡树的教程之后&#xff0c;决定学一个这个 因为它有一个很关键的好处&#xff1a;无须旋转 可以在pushup复杂度太恶心的题中做到splay做不到的…

Entity Framework 6.3 和 EF Core 3.0 路线图

尽管脱离了 .NET Core 发布循环&#xff0c;但是 EF Core 正在开发其 3.0 路线图。除此之外&#xff0c;还对原来的 Entity Framework 进行了一些重要的变更。更多服务器端的查询将 LINQ 查询转换为对应的 SQL 查询通常是比较困难的&#xff0c;甚至是不可能的。许多 QRM 只能在…

P7154 [USACO20DEC] Sleeping Cows P(DP)

主要是状态设计比较难想&#xff0c;但其实可以理性地推出来。 P7154 [USACO20DEC] Sleeping Cows P 考虑最终一个合法状态是怎么样的&#xff1a;一定是一堆小牛棚&#xff0c;一堆大奶牛&#xff0c;最大的牛棚小于最小的奶牛。 这启发我们将所有牛和牛棚放在一起&#xff0c…

AT2370-[AGC013D]Piling Up【dp】

正题 题目链接:https://www.luogu.com.cn/problem/AT2370 题目大意 有nnn个黑白球&#xff0c;但是具体颜色个数不确定&#xff0c;进行mmm次操作&#xff1a;拿出一个球然后放入黑白球各一个&#xff0c;再拿出一个球。 求最后颜色序列的种类数。 1≤n,m≤30001\leq n,m\le…

EFCore+Mysql仓储层建设(分页、多字段排序、部分字段更新)

前沿园子里已有挺多博文介绍了EFCoreMysql/MSSql如何进行使用&#xff0c;但实际开发不会把EF层放在Web层混合起来&#xff0c;需要多个项目配合结构清晰的进行分层工作&#xff0c;本文根据个人实践经验总结将各个项目进行分层&#xff0c;仅供想自己搭建,包含数据仓储以及分页…

[FWT] 时隔一年再回首FWT(快速沃尔什变换),我终于不再是个门外汉

时隔一年再回首FWT&#xff0c;我似乎有了新理解&#xff1f;&#xff1f; 添加了原理的推导&#xff0c;以前就只有模板… 文章目录引入or&#xff08;或&#xff09;卷积原理FWT_or正变换FWT_or逆变换模板and&#xff08;与&#xff09;卷积原理FWT_and正变换FWT_and逆变换模…

模板:多项式乘法(FFTNTT)

文章目录前言系数表示法和点值表示法单位根离散傅立叶变换&#xff08;DFT&#xff09;位逆序置换&#xff08;蝴蝶变换&#xff09;离散傅立叶逆变换&#xff08;IDFT&#xff09;代码NTT代码所谓快速傅立叶变换&#xff0c;就是傅立叶发明的一种快速的变换 &#xff08;逃&am…

Loj #149. 01 分数规划(01分数规划模板题)

链接 题意&#xff1a; 题解&#xff1a; 详细解法看这里 这里说个点&#xff0c;eps一定要开足够小&#xff0c;我一开始开的1e-5&#xff0c;结果就过了90%的数据&#xff0c;开到1e-7就足够了 代码&#xff1a; #include<bits/stdc.h> typedef long long ll; usin…

CF986C AND Graph(图论+二进制连边)

CF986C AND Graph \(\color{yellow}{\bigstar\texttt{Hint}}\)&#xff1a;和每个点连接的点是这个数取反后的子集&#xff0c;考虑将这个点和它的反连边&#xff0c;那么所有对应的数的子集都是同一个连通块内的。 之后的一种简单的寻找连通块就是直接对所有没有访问过的点暴力…