范围搜索 DSL_2_C

范围搜索

原题链接: AOJ_DSL_2_C

  •  题目大意

输入二维点集,从点集中输出指定区域内的所有点(包括边界) 

  • 输入

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

n表示点集内点的数量,n不超过500 000

接下来的n行输入每个点的横纵坐标,每个坐标均不超过10亿,不小于-10亿

q表示区域数,q不超过20000

接下来的q行表示每个区域的边界:sxi ≤ x ≤ txi,syi ≤ y ≤ tyi

  •  输出

对于每个区域, 按编号升序输出点集中满足条件的点的编号,每个编号占一行,每个区域输出后空一行,没有满足条件的点则输出空行,每个区域不会超过100个点

  •  样例输入

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

  • 样例输出

0
1
2
4

2
3
5

  •  解题思路

 将二维的点集转化为一维的点集,创建二叉搜索树,即将所有的点按照二叉搜索树的特点排列在数组中,所有点在数组中的索引证号为该二叉搜索树中序遍历的顺序,这个索引将用于父节点连接子节点,而IOid表示输入的顺序,仅用于输入输出。

构建二叉树时,排序、递归的作用体现在具体图像上是分割区域,反复以x和y为基准分割区域,直到把所有的点都添加到二叉树内,为后续的搜索做准备

搜索开始于根节点,如果当前节点满足条件则添加到结果集,同时还要进行对子树的搜索,如果当前节点不满足条件,则判断当前坐标在当前搜索区间的位置,并根据情况对其子树进行搜索,这里如果不做判断,搜索全部节点的话,结果虽然正确,但是会导致超时。

  • 代码与注释 

#include <cstdio>
#include <algorithm>
#include <vector>
#define NMAX 500005
#define NUL -1
using namespace std;
int n;
vector<int> result;
struct Node {
    int IOid, x, y, left, right;// id、二叉树位置、坐标、子节点
}nodes[NMAX];
/* 测试使用, 输出全部节点信息
void test(){
    printf("======================\n");
    for(int i=0;i<n;i++){
        printf("IOid:%d  id:%d  loc:%d  (%d, %d)  left:%d  right:%d\n", nodes[i].IOid, i, nodes[i].location, nodes[i].x, nodes[i].y, nodes[i].left, nodes[i].right);
    }
    printf("======================\n");
}*/

//比较函数,用于按x、y排序
bool lessByX(const Node &node1, const Node &node2){return node1.x < node2.x;}
bool lessByY(const Node &node1, const Node &node2){return node1.y < node2.y;}

/**构建二叉树*/
int buildTree(int left, int right, int depth){
    if (left>=right)
        return NUL;//递归至叶节点
    int mid = (right+left)>>1;//中值
    if (depth++ % 2)//奇数行,以y坐标为基准升序排列
        sort(nodes+left, nodes+right, lessByY);
    else sort(nodes+left, nodes+right, lessByX);//偶数行
    /*测试时用,输出每次排序后的IOid顺序
    for(int i =0;i<n;i++){
        printf("%d ", nodes[i].IOid);
    }
    printf("\n");*/
    //printf("===loc:%d left:%d right:%d mid:%d\n", loc, left, right, mid);
    nodes[mid].left = buildTree(left, mid, depth);//递归左子树
    //printf("nodes[%d]左子树返回: %d\n", mid, nodes[mid].left);
    nodes[mid].right = buildTree(mid+1, right, depth);//递归右子树
    //printf("nodes[%d]右子树返回: %d\n", mid, nodes[mid].right);
    return mid;
}

/**范围查询*/
void findNodes (int nowLoc, int xMin, int xMax, int yMin, int yMax, int depth) {
    int nowX = nodes[nowLoc].x;
    int nowY = nodes[nowLoc].y;
    if(nowX >= xMin && nowX <= xMax && nowY <= yMax && nowY >= yMin){
        result.push_back(nodes[nowLoc].IOid);//将查询到的节点保存到结果集
        // printf("found: nowLoc:%d  IOid:%d\n", nowLoc, nodes[nowLoc].IOid);
    }
    if(depth++ % 2) {//奇数行,比较y
        if(nodes[nowLoc].left!=NUL && nowY >= yMin)// y比最小值大,搜索左子树
            findNodes(nodes[nowLoc].left, xMin, xMax, yMin, yMax, depth);
        if(nodes[nowLoc].right!=NUL && nowY <= yMax)// y比最大值小,搜索右子树
            findNodes(nodes[nowLoc].right, xMin, xMax, yMin, yMax, depth);
    } else {//偶数行,比较x
        if(nodes[nowLoc].left!=NUL && nowX >= xMin)// x比最小值大,搜索左子树
            findNodes(nodes[nowLoc].left, xMin, xMax, yMin, yMax, depth);
        if(nodes[nowLoc].right!=NUL && nowX <= xMax)// x比最小值大,搜索右子树
            findNodes(nodes[nowLoc].right, xMin, xMax, yMin, yMax, depth);
    }
}

int main(){
    int xMin, xMax, yMin, yMax;
    short q;
    freopen("test.txt", "r", stdin);// 提交时删除!!!!
    freopen("out.txt", "w", stdout);// 提交时删除!!!!
    scanf("%d", &n);
    for (int i = 0;i<n;i++){
        scanf("%d%d", &nodes[i].x, &nodes[i].y);
        nodes[i].IOid = i;
    }
    int root = buildTree(0, n, 0);//构建二叉树
    //test();
    scanf("%d", &q);
    while (q--) {
        scanf("%d%d%d%d", &xMin, &xMax, &yMin, &yMax);
        findNodes(root, xMin, xMax, yMin, yMax, 0);//从二叉树的根节点执行查询
        sort(result.begin(), result.end());//对结果集进行排序
        int length = result.size();
        for(int i=0;i<length;i++){
            printf("%d\n", result[i]);
        }
        result.clear();//清空结果集
        printf("\n");
        //test();
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/the_first_snow/article/details/81207445