Full Binary Tree Picture——hihoCoder177

题目1 : Full Binary Tree Picture

时间限制: 10000ms
单点时限: 1000ms
内存限制: 256MB

描述

Let's draw a picture of full binary tree using ASCII characters. In this picture nodes are represented by '#'. A parent node connects its left child by '/' and its right child by '\'. 

For the sake of aesthetic, the nodes of the same height must be painted on the same line. And the nodes must be perfectly connected by '/' and '\'. Intersections or misplacements are not allowed. 

For example, this is the full binary tree of height 2:

  #
 / \
#   #

This is the full binary tree of height 3:

     #
    / \
   /   \
  #     #
 / \   / \
#   # #   #

This is the full binary tree of height 4:

           #
          / \
         /   \
        /     \
       /       \
      /         \
     #           #
    / \         / \
   /   \       /   \
  #     #     #     #
 / \   / \   / \   / \
#   # #   # #   # #   #

Now we build a Cartesian coordinate system for the picture. We make the root at the origin (0, 0). The positive direction of x is to the bottom and the positive direction of y is to the right.

The full binary tree of height 2 is illustrated as below. 

       0
 +-----+--------> y
 |
0+     #(0,0)
 |    / \
 |   #   #
 |(2,-2) (2,2)
 |
 v
x

Given the height of the tree and a rectangle area of the picture, your task is to find out the amount of nodes in such area. For example, assuming the height of tree is 2, the left-top corner of the rectangle area is at (0, 0) and the right-bottom corner is at (2, 2), then the area contains 2 nodes (the root and its right child) totally. 

输入

The first line contains two integers N and MN is the height of the full binary tree. M is the number of queries. (1 ≤ N ≤ 20, 1 ≤ M ≤ 100)
Each query consists of 4 integers x1y1x2 and y2. (x1y1) is the left-top corner of the area and (x2,y2) is the right-bottom corner of the area. 

输出

For each query output the amount of nodes in the area.

样例输入
2 3
0 0 0 0
0 0 2 2
0 -2 2 2
样例输出
1
2
3 

可能做得有点麻烦,思路是构造一棵树,root是(0,0),然后左节点是左子树的坐标,右节点是右子树的坐标。

然后得到area的范围坐标,再从根节点遍历全树,如果结点在area给定的区间内,那么就检查左结点与右节点是不是也在area范围内。

若结点的x坐标在范围下方,这样它的子树不可能在范围内,这就是迭代终止;若在范围上方,并且结点的x坐标在范围左边,那么其左半部分也不可能在范围内,所以只用判断右半部分;以此内推,然后将所有在范围内的结点数加起来即可。

这里有一个width的量,是当前结点的左子树与结点的距离(x距离或者y距离),为了方便直接存下来,避免每次都要算。注意:题目里的x、y轴的位置,不是我们认为的纵轴就是y,这里的纵轴是x。

int width[23];
struct Node{
    int x;
    int y;
    Node* r;
    Node* l;
    
    Node(int x, int y){
        this->x = x;
        this->y = y;
        this->r = NULL;
        this->l = NULL;
    }
};

void init(){
    width[0] = 0;
    width[1] = 0;
    width[2] = 1;
    width[3] = 2;
    width[4] = 5;
    for(int i = 5; i<23; i++){
        width[i] = width[i-1]*2 + 1;
    }
}

void insert(int h, Node * root){
    if(h == 1) return;
    root->r = new Node(root->x + width[h] + 1, root->y + width[h] + 1);
    root->l = new Node(root->x - width[h] - 1, root->y + width[h] + 1);
    insert(h-1, root->r);
    insert(h-1, root->l);
}

int check(Node *root, int x1, int y1, int x2, int y2){
    if(root == NULL) return 0;
    int x = root->x; int y = root->y;
    if(y > y2){
        return 0;
    }
    else if(y <= y2 && y >= y1 && x <= x2 && x >= x1){
        return check(root->l, x1, y1, x2, y2) + check(root->r, x1, y1, x2, y2) + 1;
    }
    else if(x > x2){
        return check(root->l, x1, y1, x2, y2);
    }
    else if(x < x1){
        return check(root->r, x1, y1, x2, y2);
    }
    else
        return check(root->r, x1, y1, x2, y2) + check(root->l, x1, y1, x2, y2);
}


int main(){
    init();
    Node* root = new Node(0, 0);
    int h; int n;
    cin>>h>>n;
    insert(h, root);
    for(int i = 0; i<n; i++){
        int x1, x2, y1, y2;
        scanf("%d %d %d %d", &x1, &y1, &x2, &y2);
        int sum = check(root, y1, x1, y2, x2);
        cout<<sum<<endl;
    }
    return 0;
}

做得很匆忙,肯定有更简单的方法,这种方法耗时耗空间。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值