挑战程序设计2 KD树

Range Query - Range Search (kD Tree)

Time Limit : 1 sec, Memory Limit : 262144 KB 
Japanese version is here

Range Search (kD Tree)

The range search problem consists of a set of attributed records S to determine which records from Sintersect with a given range.

For n points on a plane, report a set of points which are within in a given range. Note that you do not need to consider insert and delete operations for the set.

Input

n
x0 y0
x1 y1
:
xn−1 yn−1
q
sx0 tx0 sy0 ty0
sx1 tx1 sy1 ty1
:
sxq−1 txq−1 syq−1 tyq−1

The first integer n is the number of points. In the following n lines, the coordinate of the i-th point is given by two integers xi and yi.

The next integer q is the number of queries. In the following q lines, each query is given by four integers,sxitxisyityi.

Output

For each query, report IDs of points such that sxi ≤ x ≤ txi and syi ≤ y ≤ tyi. The IDs should be reported in ascending order. Print an ID in a line, and print a blank line at the end of output for the each query.

Constraints

  • 0 ≤ n ≤ 500,000
  • 0 ≤ q ≤ 20,000
  • -1,000,000,000 ≤ xysxtxsyty ≤ 1,000,000,000
  • sx ≤ tx
  • sy ≤ ty
  • For each query, the number of points which are within the range is less than or equal to 100.

Sample Input 1

6
2 1
2 2
4 2
6 2
3 3
5 4
2
2 4 0 4
4 10 2 5

Sample Output 1

0
1
2
4

2
3
5

题意:给定二维平面内n个点的坐标,查询规定区域内的点的坐标

 思路:kD树的运用

实现代码:

#define _CRT_SECURE_NO_DEPRECATE
#include<iostream>
#include<cstdio>
#include<vector>
#include<algorithm>
#include<cstring>
#include<set>
#include<string>
#include<queue>
#include<cmath>
using namespace std;
#define INF 0x3f3f3f3f
const int N_MAX = 500000;
int n,np=0;
struct point {
    int x, y,id;
    point() {}
    point(int x,int y):x(x),y(y) {}
    bool operator <(const point &p) const{
        return id < p.id;
    }
}P[N_MAX];
vector<point>vec;//别忘清空

struct KD_tree {

    int L, R, location;//location代表树中当前的节点在原来序列中的位置
    KD_tree() {}
    KD_tree(int L,int R,int location):L(L),R(R),location(location) {}
}T[N_MAX];
bool cmp_x(const point &a,const point&b) {
    return a.x < b.x;
}
bool cmp_y(const point &a, const point&b) {
    return a.y < b.y;
}

int make2DTree(int l,int r,int depth) {//区间[l,r)
    if (!(l < r))return -1;
    int mid = (l+r) / 2;
    if (depth & 1)sort(P + l, P + r, cmp_y);
    else sort(P + l, P + r, cmp_x);
    int t = np++;
    T[t].location = mid;
    T[t].L = make2DTree(l, mid, depth + 1);
    T[t].R = make2DTree(mid + 1, r, depth + 1);
    return t;
}

void find(int v,int sx,int sy,int tx,int ty,int depth) {//判断节点v是否在区域内
    int x = P[T[v].location].x;
    int y = P[T[v].location].y;
    if (x >= sx&&x <= tx&&y >= sy&&y <= ty) {
        vec.push_back(P[T[v].location]);
    }
    if (!(depth & 1)) {
        if (T[v].L != -1 && x >= sx) {
            find(T[v].L, sx, sy, tx, ty, depth + 1);
        }
        if (T[v].R != -1 && x <= tx) {
            find(T[v].R, sx, sy, tx, ty, depth + 1);
        }
    }
    else{
        if (T[v].L != -1 && y >= sy) {
            find(T[v].L, sx, sy, tx, ty, depth + 1);
        }
        if (T[v].R != -1 && y <= ty) {
            find(T[v].R, sx, sy, tx, ty, depth + 1);
        }
    }
}



int main() {
    while (scanf("%d",&n)!=EOF) {
    
        np = 0;
        for (int i = 0; i < n;i++) {
            scanf("%d%d",&P[i].x,&P[i].y);
            P[i].id = i;
        }
        int root = make2DTree(0, n, 0);
        cout <<"root:"<<root << endl;
        int q;
        scanf("%d",&q);
        while (q--) {
            vec.clear();
            int sx, tx, sy, ty;
            scanf("%d%d%d%d",&sx,&tx,&sy,&ty);
            find(root, sx, sy, tx, ty, 0);
            sort(vec.begin(), vec.end());
            for (int i = 0; i < vec.size();i++) {
                printf("%d\n",vec[i].id);
            }
            puts("");
        }
    }
    return 0;
}

 

posted on 2017-11-01 21:42  ZefengYao  阅读(201)  评论(0编辑  收藏  举报

导航