DSL_2_C:Range Search (kD Tree)

题目链接: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 <iostream>
#include <cstdio>
#include <vector>
#include <algorithm>
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<Point> A;
int n,q,np=0;

bool cxddx(Point xx, Point yy){
	return xx.x<yy.x;
}
bool cxddy(Point xx, Point yy){
	return xx.y<yy.y;
}

int makekdtree(int left,int right,int depth){
	if(left>=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<n;i++){
		scanf("%d %d", &x, &y);
		p[i] = Point(i, x, y);
		T[i].l = T[i].r = T[i].p = NIL;
	}
	int root=makekdtree(0,n,0);
	
	scanf("%d", &q);
	int sx,sy,tx,ty;
	while(q--){
		scanf("%d %d %d %d", &sx, &tx, &sy, &ty);
		A.clear();
		find(root,sx,sy,tx,ty,0);
		sort(A.begin(),A.end());
		int len=A.size();
		for(int i=0;i<len;i++) A[i].print();
		cout<<endl;
	}
	return 0;
}

 

错点:

 

1.使用scanf printf而不是cin cout

2.输出的时候输出id即可

3.point排序的比较函数要自己写

4.要初始化T数组

最近看了一些微信小程序,觉得贼有意思,耽误了几天blog,炒鸡愧疚,于是决定再去玩一下小程序 :D 

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
{"method":"/algo/result","request":"{"user_input_params":{"cur_hour":"'1000'","limit_offset":"0","limit_size":"500","cur_day":"'20230605'"},"version":"main","tid":"generate_direct_purchase_task_v2","sid":"OMS"}","dsl":"cluster:bigdata GET store_product_auto_purchase_hourly/_search { "size" : 0, "query" : { "bool" : { "filter" : [ { "bool" : { "must" : [ { "term" : { "cur_day" : { "value" : "20230605", "boost" : 1.0 } } }, { "term" : { "cur_hour" : { "value" : "1000", "boost" : 1.0 } } } ], "adjust_pure_negative" : true, "boost" : 1.0 } } ], "adjust_pure_negative" : true, "boost" : 1.0 } }, "_source" : { "includes" : [ ], "excludes" : [ ] }, "aggregations" : { "result" : { "composite" : { "size" : 10000, "sources" : [ { "supplier_id" : { "terms" : { "field" : "supplier_id", "missing_bucket" : false, "order" : "asc" } } }, { "city_zip" : { "terms" : { "field" : "city_zip", "missing_bucket" : false, "order" : "asc" } } }, { "city_order_create_type" : { "terms" : { "field" : "city_order_create_type", "missing_bucket" : false, "order" : "asc" } } }, { "city_order_create" : { "terms" : { "field" : "city_order_create", "missing_bucket" : false, "order" : "asc" } } }, { "city_order_confirm_end" : { "terms" : { "field" : "city_order_confirm_end", "missing_bucket" : false, "order" : "asc" } } }, { "supply_model" : { "terms" : { "field" : "supply_model", "missing_bucket" : false, "order" : "asc" } } }, { "dc_store_delivery_start_time" : { "terms" : { "field" : "dc_store_delivery_start_time", "missing_bucket" : false, "order" : "asc" } } }, { "plan_sale_base_start" : { "terms" : { "field" : "plan_sale_base_start", "missing_bucket" : false, "order" : "asc" } } }, { "rule_detail_type" : { "terms" : { "field" : "rule_detail_type", "missing_bucket" : false, "order" : "asc" } } }, { "delivery_waves" : { "terms" : { "field" : "delivery_waves", "missing_bucket" : false, "order" : "asc" } } } ] }, "aggregations" : { "r_bucket_sort" : { "bucket_sort" : { "sort" : [ ], "from" : 0, "size" : 500, "gap_policy" : "SKIP" } } } } }}","total":0,"result":"[]"} 将上面的json转化为python字典
最新发布
06-06

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值