Full Binary Tree Picture hiho一下第 177 周

题意: 题目中给出画二叉树的画法,然后说以第一层的点为坐标原点,向下为 x 轴正方向,向右为 y 轴正方向,这样二叉树中的每一个点就都有了坐标。最后,题目中给出一系列的矩形的左上角和右下角的坐标,问落在给出矩形中的结点有几个。

思路: 容易联想到利用二叉树,利用对二叉树的遍历来得到结果。不过首先,我们需要知道二叉树中每个结点的坐标。
N = 1 时,只有一层,结点坐标为 (0, 0);
N = 2 时,有两层:

  • 第一层结点坐标为 (0, 0);
  • 第二层结点坐标为 (2, -2) 和 (2, 2)。

N = 3 时,有三层:

  • 第一层结点坐标为 (0, 0);
  • 第二层结点坐标为 (3, -3) 和 (3, 3);
  • 第三层结点坐标为 (5, -5)、(5, -1)、(5, 1) 和 (5, 5)。

N = 4 时,有四层:

  • 第一层结点坐标为 (0, 0);
  • 第二层结点坐标为 (6, -6) 和 (6, 6);
  • 第三层结点坐标为 (9, -9)、(9, -3)、(9, 3) 和 (9, 9);
  • 第四层结点坐标为 (11, -11)、(11, -7)、(11, -5)、(11, -1)、(11, 1)、(11, 5)、(11, 7) 和 (11, 11)。

仔细观察我们能够发现子结点的坐标可以由父节点的坐标加上 (t, +t) 或 (t, -t)(其中 t 为以子节点为顶点的子树的高)。
子树的高和子树的层数(N)有关系,这边直接上结果:

t=133×2N2 N = 1  N = 2   N>2

当二叉树上的所有结点的坐标建立好后,根据所给的矩形对二叉树进行遍历。
当结点在矩形的左边时,遍历它的右结点;
当结点在矩形的右边时,遍历它的左结点;
当结点在矩形的下方时,则无需继续遍历。

注意坐标轴方向,一开始我就错在了坐标轴方向上。。。
代码:

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<stack>
#include<queue>
#include<utility>
#include<vector>
#include<cmath>
#include<set>
#include<map>
#include<iostream>
#include<algorithm>
#include<sstream>
using namespace std;
typedef long long LL;

const int INF = 0x3f3f3f3f;

struct Point{
    int x, y;
};

int N, M;
Point tree[1050000];
int xl, yl, xr, yr;
int ans;

void Build(int x, int y, int k, int n)
{
    if(n == 0) return;
    tree[k].x = x;
    tree[k].y = y;
    //printf("tree[%d] = %d, %d\n", k, x, y);
    int newx, newy;
    if(n == 2){
        Build(x+2, y+2, 2*k+1, n-1);  //向右走
        Build(x+2, y-2, 2*k, n-1);   //向左走
    }
    else{
        Build(x+3*pow(2,n-3), y+3*pow(2,n-3), 2*k+1, n-1);  //向右走
        Build(x+3*pow(2,n-3), y-3*pow(2,n-3), 2*k, n-1);   //向左走
    }
}

void Search(int k)
{
    if(tree[k].x >xr) return ;
    if(tree[k].x == INF) return;
    if(tree[k].x>=xl && tree[k].x<=xr && tree[k].y>=yl && tree[k].y<=yr) ans++;
    if(tree[k].y < yl){
        Search(2*k+1);   //往右找
    }
    else if(tree[k].y > yr){
        Search(2*k);   //往左找
    }
    else if(tree[k].y>=yl && tree[k].y<=yr){  //往两边延伸
        Search(2*k);
        Search(2*k+1);
    }
}

int main()
{
    //freopen("in.txt", "r", stdin);
    while(scanf("%d%d", &N, &M) == 2){
        for(int i=1; i<=((1<<(N+1))-1); i++){
            tree[i].x = INF;
            tree[i].y = INF;
        }
        Build(0, 0, 1, N);
        while(M--){
            scanf("%d%d%d%d", &xl, &yl, &xr, &yr);
            ans = 0;
            Search(1);
            printf("%d\n", ans);
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值