题目链接:http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=DSL_2_C
题目给出了一些点的坐标,然后给出一个二维的矩形范围,判断哪些点在这个范围内;
比如,给出一些二维点的坐标,然后求出1<=x<=5而且2<=y<=6的所有点;
就是一个范围搜索的题目,需要用到KD Tree;就是k维树,在建立好kd tree后不需要对tree进行增加删除节点的操作,简化一些:
在此之前,先抛开题目先学习一下kd tree是什么,用于解决什么问题:
kd tree是为了解决如下情况:每一个节点都有很多数据,比如A点(x1,x2,x3,x4,x5),有5个数据,B点也有5个数据,每个点都有5个数据,现在给出很多点,如果我希望快速找到我想找的那个点,如果每个点遍历,太慢,我该怎么做。
当每个点只有1个数据的时候,其实就转化成了在一组数据中寻找某个数据的问题,我们可以用二叉搜索树来解决这个问题。而kd tree也是利用的这个思想:
所以,首先,在我的理解,1D Tree(1维树)可以看做就是BST(二叉搜索树);
我们在构建BST的时候,在每一层,都保证根节点的左儿子比根节点小,右孩子比根节点大。比较的值只有一个,看做是x值。
当需要比较的值不止1个,有2个值甚至更多时,我们可以依次比较这两个值,比如在二叉搜索树的第一层比较x的值,第二层比较y的值,以此类推,奇数层比x,偶数层比y。我保证能做到:【深度为偶数的节点,其左孩子的x比他大,右孩子的x比他小;深度为奇数的节点,其左孩子的y比他大,右孩子的y比他小】更高的维度也可以继续类推。这样的方法不一定太好,因为可能数据分布的很不均匀,有一个比较好的分割方法是求出数据在每个维度的方差,然后选方差最大的那个维度进行比较,这样可以尽可能使树的左右两边比较均衡。
在比较的时候,为了保证左右子树的平衡,我们每次都选取中位数来做子树的根。
具体代码如下:
#include
#include
#include
#include
using namespace std;
class Node {
public :
int location;
int p, l, r;
Node() {};
};
class Point {
public:
int id, x, y;
Point() {};
Point(int id, int x, int y) :id(id), x(x), y(y) {};
bool operator < (const Point &p) const {
return id < p.id;
}
void print(){
printf("%d\n", id);
}
};
const int maxx = 1000010;
const int NIL = -1;
Point p[maxx];
Node T[maxx];
vector A;
int n,q,np=0;
bool cxddx(Point xx, Point yy){
return xx.x=right) return NIL;
int mid = (left+right)/2;
int t=np++;
if(depth%2==0){
sort(p+left,p+right,cxddx);
}
else{
sort(p+left,p+right,cxddy);
}
T[t].location=mid;
T[t].l=makekdtree(left,mid,depth+1);
T[t].r=makekdtree(mid+1,right,depth+1);
return t;
}
void find(int v,int sx,int sy,int tx,int ty,int depth){
int x=p[T[v].location].x,y=p[T[v].location].y;
if(sx<=x && sy<=y && tx>=x && ty>=y){
A.push_back(p[T[v].location]);
}
if(depth%2==0){
if(T[v].l!=NIL){
if(sx<=x) find(T[v].l,sx,sy,tx,ty,depth+1);
}
if(T[v].r!=NIL){
if(tx>=x) find(T[v].r,sx,sy,tx,ty,depth+1);
}
}
else{
if(T[v].l!=NIL){
if(sy<=y) find(T[v].l,sx,sy,tx,ty,depth+1);
}
if(T[v].r!=NIL){
if(ty>=y) find(T[v].r,sx,sy,tx,ty,depth+1);
}
}
return ;
}
int main(){
int x,y;
scanf("%d", &n);
for(int i=0;i
错点:
1.使用scanf printf而不是cin cout
2.输出的时候输出id即可
3.point排序的比较函数要自己写
4.要初始化T数组
最近看了一些微信小程序,觉得贼有意思,耽误了几天blog,炒鸡愧疚,于是决定再去玩一下小程序 :D