KD-Tree,用来解决多维空间中的问题,其实就是优化暴力(逃

一般cdq能做的它都能做,而且。。。既然是优化暴力,那就学习一下了

对与几个n维点,我们将它每一维分割,建立一颗二叉树,方便我们搜索剪枝

它好像插入比较麻烦,和替罪羊一样暴力重构,博主蒟蒻不会啦

KD-Tree能解决的问题:平面上点对最小,最大距离,k大距离(包括曼哈顿距离和欧式距离)

当然这是我的理解,可能会有偏差

KD-Tree基本模板:

  1. struct node{
  2. int d[2],l,r,mx[2],mn[2],id;
  3. friend bool operator < (node a,node b){
  4. return a.d[now]<b.d[now];
  5. }
  6. }ask,tr[MAXN];
  7. struct KD_TREE{
  8. void update(int x){
  9. int l=tr[x].l,r=tr[x].r;
  10. for(int i=0;i<=1;i++){
  11. tr[x].mn[i]=tr[x].mx[i]=tr[x].d[i];
  12. if(l!=0){
  13. tr[x].mn[i]=min(tr[x].mn[i],tr[l].mn[i]);
  14. tr[x].mx[i]=max(tr[x].mx[i],tr[l].mx[i]);
  15. }
  16. if(r!=0){
  17. tr[x].mn[i]=min(tr[x].mn[i],tr[r].mn[i]);
  18. tr[x].mx[i]=max(tr[x].mx[i],tr[r].mx[i]);
  19. }
  20. }
  21. }
  22. int dis(node a,node b){
  23. int res=0;
  24. for(int i=0;i<=1;i++){
  25. res+=power(a.d[i]-b.d[i]);
  26. }
  27. return res;
  28. }
  29. int get_dis(node a){
  30. int res=0;
  31. for(int i=0;i<=1;i++){
  32. res+=max(power(a.mx[i]-ask.d[i]),power(a.mn[i]-ask.d[i]));
  33. }
  34. return res;
  35. }
  36. void build(int &rt,int l,int r,int d){
  37. int mid=(l+r)>>1;
  38. now=d;
  39. nth_element(tr+l,tr+mid,tr+r+1);
  40. if(l<mid) build(tr[mid].l,l,mid-1,d^1);
  41. if(r>mid) build(tr[mid].r,mid+1,r,d^1);
  42. update(mid);
  43. rt=mid;
  44. }
  45. void query(int x){
  46. if(!x) return ;
  47. int sum_l=inf,sum_r=inf,dist=dis(tr[x],ask);
  48. if(tr[x].l) sum_l=get_dis(tr[tr[x].l]);
  49. if(tr[x].r) sum_r=get_dis(tr[tr[x].r]);
  50. if(dist>-q.top()){
  51. q.pop();
  52. q.push(-dist);
  53. }
  54. if(sum_l>sum_r){
  55. if(sum_l>=-q.top()) query(tr[x].l);
  56. if(sum_r>=-q.top()) query(tr[x].r);
  57. }else{
  58. if(sum_r>=-q.top()) query(tr[x].r);
  59. if(sum_l>=-q.top()) query(tr[x].l);
  60. }
  61. }
  62. }KD_Tree;

其中dis和get_dis是随题而定,其他的基本不变

例题:Hide and Seek

题目大意:给出平面内几个点的坐标,求曼哈顿距离最小值

挺水的,上代码:

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstring>
  4. #include<algorithm>
  5. #include<cmath>
  6. #define MAXN 500005
  7. #define inf 0x7fffffff
  8. using namespace std;
  9. int read(){
  10. int x=0;char ch=getchar();
  11. while(ch<'0'||ch>'9'){ch=getchar();}
  12. while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
  13. return x;
  14. }
  15. int max(int a,int b){return a>b?a:b;}
  16. int min(int a,int b){return a<b?a:b;}
  17. int abs(int a){return a<0?-a:a;}
  18. int n,now,root,ans=inf;
  19. struct node{
  20. int d[2],l,r,mx[2],mn[2];
  21. friend bool operator < (node a,node b){
  22. return a.d[now]<b.d[now];
  23. }
  24. friend int dis(node a,node b){
  25. return abs(a.d[0]-b.d[0])+abs(a.d[1]-b.d[1]);
  26. }
  27. }tr[MAXN];
  28. struct KD_TREE{
  29. node p[MAXN],t;
  30. int ans;
  31. private:
  32. void update(int x){
  33. int l=p[x].l,r=p[x].r;
  34. for(int i=0;i<=1;i++){
  35. if(l!=0){
  36. p[x].mn[i]=min(p[x].mn[i],p[l].mn[i]);
  37. p[x].mx[i]=max(p[x].mx[i],p[l].mx[i]);
  38. }
  39. if(r!=0){
  40. p[x].mn[i]=min(p[x].mn[i],p[r].mn[i]);
  41. p[x].mx[i]=max(p[x].mx[i],p[r].mx[i]);
  42. }
  43. }
  44. }
  45. int get_min(node x){
  46. int sum=0;
  47. for(int i=0;i<=1;i++){
  48. sum+=max(x.mn[i]-t.d[i],0);
  49. sum+=max(t.d[i]-x.mx[i],0);
  50. }
  51. return sum;
  52. }
  53. int get_max(node x){
  54. int sum=0;
  55. for(int i=0;i<=1;i++){
  56. sum+=max(abs(x.mn[i]-t.d[i]),abs(x.mx[i]-t.d[i]));
  57. }
  58. return sum;
  59. }
  60. public:
  61. void build(int &rt,int l,int r,int d){
  62. int mid=l+r>>1;
  63. now=d;
  64. nth_element(tr+l,tr+mid,tr+r+1);
  65. p[mid]=tr[mid];
  66. for(int i=0;i<=1;i++)
  67. p[mid].mx[i]=p[mid].mn[i]=p[mid].d[i];
  68. if(l<mid) build(p[mid].l,l,mid-1,d^1);
  69. if(r>mid) build(p[mid].r,mid+1,r,d^1);
  70. update(mid);
  71. rt=mid;
  72. }
  73. void query_min(int k){
  74. int dist=dis(p[k],t);
  75. if(dist) ans=min(ans,dist);
  76. int sum_l=inf,sum_r=inf;
  77. if(p[k].l) sum_l=get_min(p[p[k].l]);
  78. if(p[k].r) sum_r=get_min(p[p[k].r]);
  79. if(sum_l>sum_r){
  80. if(sum_r<ans) query_min(p[k].r);
  81. if(sum_l<ans) query_min(p[k].l);
  82. }else{
  83. if(sum_l<ans) query_min(p[k].l);
  84. if(sum_r<ans) query_min(p[k].r);
  85. }
  86. }
  87. void query_max(int k){
  88. ans=max(ans,dis(p[k],t));
  89. int sum_l=-inf,sum_r=-inf;
  90. if(p[k].l) sum_l=get_max(p[p[k].l]);
  91. if(p[k].r) sum_r=get_max(p[p[k].r]);
  92. if(sum_l>sum_r){
  93. if(sum_l>ans) query_max(p[k].l);
  94. if(sum_r>ans) query_max(p[k].r);
  95. }else{
  96. if(sum_r>ans) query_max(p[k].r);
  97. if(sum_l>ans) query_max(p[k].l);
  98. }
  99. }
  100. }KD_Tree;
  101. int main(){
  102. n=read();
  103. for(int i=1;i<=n;i++){
  104. tr[i].d[0]=read();
  105. tr[i].d[1]=read();
  106. }
  107. KD_Tree.build(root,1,n,0);
  108. for(int i=1;i<=n;i++){
  109. KD_Tree.t=tr[i];
  110. KD_Tree.ans=inf;
  111. KD_Tree.query_min(root);
  112. int minn=KD_Tree.ans;
  113. KD_Tree.ans=-inf;
  114. KD_Tree.query_max(root);
  115. int maxx=KD_Tree.ans;
  116. ans=min(ans,maxx-minn);
  117. }
  118. printf("%d\n",ans);
  119. return 0;
  120. }

例题:JZPFAR:

题目大意:给定平面上n个点坐标以及m次询问,每一次输出欧式距离距目标点第k大的点的标号

跟上一个差不多,估价函数变了,

第k大的话,维护一个有k个元素的堆,每次有更优的就pop队顶,最终top就是答案

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstring>
  4. #include<algorithm>
  5. #include<cmath>
  6. #include<queue>
  7. #define MAXN 500005
  8. #define inf 0x7fffffff
  9. #define int long long
  10. using namespace std;
  11. int read(){
  12. int x=0,f=1;char ch=getchar();
  13. while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
  14. while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
  15. return x*f;
  16. }
  17. int max(int a,int b){return a>b?a:b;}
  18. int min(int a,int b){return a<b?a:b;}
  19. int abs(int a){return a<0?-a:a;}
  20. int power(int a){return a*a;}
  21. int n,m,now,root,k;
  22. struct data{
  23. int dis,id;
  24. friend bool operator < (data a,data b){
  25. return a.dis==b.dis?a.id<a.id:a.dis>b.dis;
  26. }
  27. };
  28. priority_queue< data > q;
  29. struct node{
  30. int d[2],l,r,mx[2],mn[2],id;
  31. friend bool operator < (node a,node b){
  32. return a.d[now]<b.d[now];
  33. }
  34. }ask,tr[MAXN],p[MAXN];
  35. struct KD_TREE{
  36. private:
  37. void update(int x){
  38. int l=tr[x].l,r=tr[x].r;
  39. for(int i=0;i<=1;i++){
  40. tr[x].mn[i]=tr[x].mx[i]=tr[x].d[i];
  41. if(l!=0){
  42. tr[x].mn[i]=min(tr[x].mn[i],tr[l].mn[i]);
  43. tr[x].mx[i]=max(tr[x].mx[i],tr[l].mx[i]);
  44. }
  45. if(r!=0){
  46. tr[x].mn[i]=min(tr[x].mn[i],tr[r].mn[i]);
  47. tr[x].mx[i]=max(tr[x].mx[i],tr[r].mx[i]);
  48. }
  49. }
  50. }
  51. int dis(node a,node b){
  52. int res=0;
  53. for(int i=0;i<=1;i++){
  54. res+=power(a.d[i]-b.d[i]);
  55. }
  56. return res;
  57. }
  58. int calc(int x){
  59. if(x==0) return -2;
  60. int res=0;
  61. for(int i=0;i<=1;i++){
  62. res+=max(power(tr[x].mx[i]-ask.d[i]),power(tr[x].mn[i]-ask.d[i]));
  63. }
  64. return res;
  65. }
  66. public:
  67. void build(int &rt,int l,int r,int d){
  68. int mid=(l+r)>>1;
  69. now=d;
  70. nth_element(p+l,p+mid,p+r+1);
  71. tr[mid]=p[mid];
  72. if(l<mid) build(tr[mid].l,l,mid-1,d^1);
  73. if(r>mid) build(tr[mid].r,mid+1,r,d^1);
  74. update(mid);
  75. rt=mid;
  76. }
  77. void query(int x){
  78. //cout<<x<<endl;
  79. if(!x) return ;
  80. int sum_l=calc(tr[x].l),sum_r=calc(tr[x].r),dist=dis(tr[x],ask);
  81. //cout<<sum_l<<' '<<sum_r<<' '<<dist<<endl;
  82. if(dist>q.top().dis||(dist==q.top().dis&&tr[x].id<q.top().id)){
  83. q.pop();
  84. //cout<<dist<<' '<<tr[x].id<<endl;
  85. q.push((data){dist,tr[x].id});
  86. }
  87. if(sum_l>sum_r){
  88. if(sum_l>=q.top().dis) query(tr[x].l);
  89. if(sum_r>=q.top().dis) query(tr[x].r);
  90. }else{
  91. if(sum_r>=q.top().dis) query(tr[x].r);
  92. if(sum_l>=q.top().dis) query(tr[x].l);
  93. }
  94. }
  95. }KD_Tree;
  96. signed main(){
  97. n=read();
  98. for(int i=1;i<=n;i++){
  99. p[i].d[0]=read();
  100. p[i].d[1]=read();
  101. p[i].id=i;
  102. }
  103. KD_Tree.build(root,1,n,0);
  104. //cout<<root<<endl;
  105. m=read();
  106. for(int i=1;i<=m;i++){
  107. ask.d[0]=read();
  108. ask.d[1]=read();
  109. k=read();
  110. while(!q.empty()) q.pop();
  111. for(int i=1;i<=k;i++)
  112. q.push((data){-1,0});
  113. // q.push(make_pair(-1,0));
  114. KD_Tree.query(root);
  115. //cout<<q.top().first<<endl;
  116. printf("%lld\n",q.top().id);
  117. }
  118. return 0;
  119. }

进阶:K远点对

题目大意:已知平面内 N 个点的坐标,求欧氏距离下的第 K 远点对。

和上一个一样,只不过这一次我们要对每个点query一遍,

其中维护一个2k的堆(因为会重复算),最终堆顶就是答案

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstring>
  4. #include<algorithm>
  5. #include<cmath>
  6. #include<queue>
  7. #define MAXN 100005
  8. #define inf 0x7fffffff
  9. #define int long long
  10. using namespace std;
  11. int read(){
  12. int x=0,f=1;char ch=getchar();
  13. while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
  14. while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
  15. return x*f;
  16. }
  17. int max(int a,int b){return a>b?a:b;}
  18. int min(int a,int b){return a<b?a:b;}
  19. int abs(int a){return a<0?-a:a;}
  20. int power(int a){return a*a;}
  21. int n,m,now,root,k;
  22. struct data{
  23. int dis;
  24. friend bool operator < (data a,data b){
  25. return a.dis<b.dis;
  26. }
  27. };
  28. priority_queue<int> q;
  29. struct node{
  30. int d[2],l,r,mx[2],mn[2],id;
  31. friend bool operator < (node a,node b){
  32. return a.d[now]<b.d[now];
  33. }
  34. }ask,tr[MAXN];
  35. struct KD_TREE{
  36. void update(int x){
  37. int l=tr[x].l,r=tr[x].r;
  38. for(int i=0;i<=1;i++){
  39. tr[x].mn[i]=tr[x].mx[i]=tr[x].d[i];
  40. if(l!=0){
  41. tr[x].mn[i]=min(tr[x].mn[i],tr[l].mn[i]);
  42. tr[x].mx[i]=max(tr[x].mx[i],tr[l].mx[i]);
  43. }
  44. if(r!=0){
  45. tr[x].mn[i]=min(tr[x].mn[i],tr[r].mn[i]);
  46. tr[x].mx[i]=max(tr[x].mx[i],tr[r].mx[i]);
  47. }
  48. }
  49. }
  50. int dis(node a,node b){
  51. int res=0;
  52. for(int i=0;i<=1;i++){
  53. res+=power(a.d[i]-b.d[i]);
  54. }
  55. return res;
  56. }
  57. int get_dis(node a){
  58. int res=0;
  59. for(int i=0;i<=1;i++){
  60. res+=max(power(a.mx[i]-ask.d[i]),power(a.mn[i]-ask.d[i]));
  61. }
  62. return res;
  63. }
  64. void build(int &rt,int l,int r,int d){
  65. int mid=(l+r)>>1;
  66. now=d;
  67. nth_element(tr+l,tr+mid,tr+r+1);
  68. if(l<mid) build(tr[mid].l,l,mid-1,d^1);
  69. if(r>mid) build(tr[mid].r,mid+1,r,d^1);
  70. update(mid);
  71. rt=mid;
  72. }
  73. void query(int x){
  74. if(!x) return ;
  75. int sum_l=inf,sum_r=inf,dist=dis(tr[x],ask);
  76. if(tr[x].l) sum_l=get_dis(tr[tr[x].l]);
  77. if(tr[x].r) sum_r=get_dis(tr[tr[x].r]);
  78. if(dist>-q.top()){
  79. q.pop();
  80. q.push(-dist);
  81. }
  82. if(sum_l>sum_r){
  83. if(sum_l>=-q.top()) query(tr[x].l);
  84. if(sum_r>=-q.top()) query(tr[x].r);
  85. }else{
  86. if(sum_r>=-q.top()) query(tr[x].r);
  87. if(sum_l>=-q.top()) query(tr[x].l);
  88. }
  89. }
  90. }KD_Tree;
  91. signed main(){
  92. n=read(),k=read();
  93. for(int i=1;i<=n;i++){
  94. tr[i].d[0]=read();
  95. tr[i].d[1]=read();
  96. tr[i].id=i;
  97. }
  98. KD_Tree.build(root,1,n,0);
  99. for(int i=1;i<=2*k;i++) q.push(inf);
  100. for(int i=1;i<=n;i++){
  101. ask=tr[i];
  102. KD_Tree.query(root);
  103. }
  104. printf("%lld\n",-q.top());
  105. return 0;
  106. }

模板:KD-Tree的更多相关文章

  1. [模板] K-D Tree

    K-D Tree K-D Tree可以看作二叉搜索树的高维推广, 它的第 \(k\) 层以所有点的第 \(k\) 维作为关键字对点做出划分. 为了保证划分均匀, 可以以第 \(k\) 维排名在中间的节 ...

  2. k-d tree模板练习

    1. [BZOJ]1941: [Sdoi2010]Hide and Seek 题目大意:给出n个二维平面上的点,一个点的权值是它到其他点的最长距离减最短距离,距离为曼哈顿距离,求最小权值.(n< ...

  3. AOJ DSL_2_C Range Search (kD Tree)

    Range Search (kD Tree) The range search problem consists of a set of attributed records S to determi ...

  4. 【BZOJ-2648&2716】SJY摆棋子&天使玩偶 KD Tree

    2648: SJY摆棋子 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 2459  Solved: 834[Submit][Status][Discu ...

  5. BZOJ2648/2716:SJY摆棋子/[Violet]天使玩偶(K-D Tree)

    Description 这天,SJY显得无聊.在家自己玩.在一个棋盘上,有N个黑色棋子.他每次要么放到棋盘上一个黑色棋子,要么放上一个白色棋子,如果是白色棋子,他会找出距离这个白色棋子最近的黑色棋子. ...

  6. k-d tree 学习笔记

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

  7. K-D Tree

    这篇随笔是对Wikipedia上k-d tree词条的摘录, 我认为解释得相当生动详细, 是一篇不可多得的好文. Overview A \(k\)-d tree (short for \(k\)-di ...

  8. K-D Tree题目泛做(CXJ第二轮)

    题目1: BZOJ 2716 题目大意:给出N个二维平面上的点,M个操作,分为插入一个新点和询问到一个点最近点的Manhatan距离是多少. 算法讨论: K-D Tree 裸题,有插入操作. #inc ...

  9. k-d Tree in TripAdvisor

    Today, TripAdvisor held a tech talk in Columbia University. The topic is about k-d Tree implemented ...

  10. k-d tree算法

    k-d树(k-dimensional树的简称),是一种分割k维数据空间的数据结构.主要应用于多维空间关键数据的搜索(如:范围搜索和最近邻搜索). 应用背景 SIFT算法中做特征点匹配的时候就会利用到k ...

随机推荐

  1. for in循环介绍以及陷阱

    大家都知道在JavaScript中提供了两种方式迭代对象: (1)for 循环: (2)for..in循环: 使用for循环进行迭代数组对象,想必大家都已经司空见惯了.但是,使用for.. in循环时 ...

  2. 「STL」bitset正传

    前言 之前一些需要转二进制来解决的题目我看到很多大佬用了bitset. 然而我并不会这东西.看上去很高级的样子…… 改题改累了来学习一下233. 正文 一.bitset的构造 bitset有三种构造方 ...

  3. js 忘记密码发送短信记录cookie

    <div class="forgetPwdBox" style="display:none"> <div class="forTit ...

  4. idea激活破解

    下载链接:https://pan.baidu.com/s/1BADk1MCm0YxtB6zoX0DivA 提取码 ze9m将破解补丁放到bin文件中jetbrains-all.jar 在这俩个文件最后 ...

  5. Python3简介

    Python3简介 Python 是一个高层次的结合了解释性.编译性.互动性和面向对象的脚本语言. Python 的设计具有很强的可读性,相比其他语言经常使用英文关键字,其他语言的一些标点符号,它具有 ...

  6. Requests+Excel接口自动化测试(Python)

    一.框架结构:  工程目录 二.Case文件设计 三.基础包 base 3.1 封装get/post请求(runmethon.py) import requests import json class ...

  7. 面试系列 31 zk都有哪些使用场景

    大致来说,zk的使用场景如下,我就举几个简单的,大家能说几个就好了: (1)分布式协调:这个其实是zk很经典的一个用法,简单来说,就好比,你A系统发送个请求到mq,然后B消息消费之后处理了.那A系统如 ...

  8. 面试系列九 es 提高查询效率

    ,es性能优化是没有什么银弹的,啥意思呢?就是不要期待着随手调一个参数,就可以万能的应对所有的性能慢的场景.也许有的场景是你换个参数,或者调整一下语法,就可以搞定,但是绝对不是所有场景都可以这样. 一 ...

  9. No packages marked for update

    问题:用yum安装docker,更新yum存储时,报以下错误,导致yum坏了 [root@localhost yum.repos.d]# vi docker.repo [root@localhost ...

  10. jvisualvm图解【转】

    jvisualvm图解[转]   http://blog.csdn.net/a19881029/article/details/8432368 jvisualvm能干什么:监控内存泄露,跟踪垃圾回收, ...