[Hihocoder week177]Full Binary Tree Picture

本文介绍了一种O(N)复杂度的全二叉树图像绘制算法,该算法通过遍历每一层节点并计算指定范围内的节点数量来优化效率。文章详细解释了算法的工作原理,并提供了一个具体的实现代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Hihocoder Week 177 — Full Binary Tree Picture (O(N)复杂度)

Problem

题目链接

Idea

Some solutions gives by others need to traverse the whole full binary tree and check each nodes to get the answer. Here we put forward a solution whose time complexity is O(N) .

The key idea of the solution is to get the count of nodes in the range of [y1, y2] in each layer. If the x coordinate of the layer is in the range of [x1, x2], we will add the count to the answer.

Note that we can mark nodes in a full binary tree with numbers from 1 to 2N1, and the numbers in each layer is a consecutive sequence. Satisfied nodes in one layer form a sub-sequence of the whole sequence. Thus, given start and the end of the satisfied nodes, we can get the count of satisfied nodes. snode and enode denote the start node ant the end node of the satisfied nodes sequence.

In the solution, we use two variables to capture the indexes of snode and enode, i.e., y_min and y_max. Their indexes are stored in y_min_idx and y_max_idx. At the start of the algorithm, we initialize their values as y_min = y_max = 0 and y_min_idx = y_max_idx = 0, for we start to go from the root.

Our algorithm can be divided into two procedures.

  1. In the first procedure, y_min==y_max. And we need to check whether snode and enode can go two side (left child and right child). We can see that only if y_min/y_max is in the range of [y1, y2], we can bi-path snode and enode to left child and right child. This is because the range between them potentially have an intersection with [y1, y2]. Otherwise y_min/y_max is in the outside of [y1, y2]. This time, y_min/y_max need to go close to y1 or y2.

  2. In the second procedure, y_min!=y_max. And we need to check y_min and y_max to make sure whether they are in the range of [y1, y2]. If not, for y_min, snode will go to its right child; for y_max, enode will go to its left child. We have mentioned that [y_min, y_max] may have an intersection with [y1, y2]. If y_min is out of the range, we set temp snode to its right sibling node. If y_max is out of the range, we set temp enode to its left sibling node. If the x coordinate of the current layer is in the range of [x1, x2], we add count of nodes between snode and enode.

The step (height difference) between two adjcent layer is easy to compute, and we omit here.

Code

// time: 0ms, momory: 0MB
#include <string.h>
#include <stdio.h>

int n, m;
int x1[110];
int y1[110];
int x2[110];
int y2[110];

int height[20];

void cal(int a1, int b1, int a2, int b2){
    int i; 

    int ans = 0;
    int x = 0;
    int y_max = 0;
    int y_min = 0;
    int y_max_idx = 1;
    int y_min_idx = 1;

    int tmp_max, tmp_min;

    if(a1 > a2 || b1 > b2){
        printf("0\n");
        return;
    }

    for(i = 1; i <= n; i++){

        if(x > a2)
            break;

        if(y_min == y_max){
            // check whether in the range
            if(y_min >= b1 && y_min <= b2){
                //good, go two sides
                if(x >= a1){
                    ans++;
                }
                y_min -= (height[i] + 1);
                y_min_idx = y_min_idx * 2;

                y_max += (height[i] + 1);
                y_max_idx = y_max_idx * 2 + 1;

            } else {
                // bad , both go one side
                if(y_min < b1) {
                    // both go right
                    y_min += (height[i] + 1);
                    y_min_idx = y_min_idx * 2 + 1;

                    y_max += (height[i] + 1);
                    y_max_idx = y_max_idx * 2 + 1;
                } else {
                    // both go left
                    y_min -= (height[i] + 1);
                    y_min_idx = y_min_idx * 2;

                    y_max -= (height[i] + 1);
                    y_max_idx = y_max_idx * 2;
                }
            }
        } else {
            // has go two side
            tmp_max = (y_max > b2) ? (y_max_idx - 1) : y_max_idx;
            tmp_min = (y_min < b1) ? (y_min_idx + 1) : y_min_idx;

            // if(tmp_max >= tmp_min) {
                if(x >= a1){
                    ans += (tmp_max - tmp_min + 1);
                }
            // }

            if(y_max > b2){
                // go left
                y_max -= (height[i] + 1);
                y_max_idx = y_max_idx * 2;
            } else {
                // continue go right
                y_max += (height[i] + 1);
                y_max_idx = y_max_idx * 2 + 1;
            }

            if(y_min < b1) {
                // go right
                y_min += (height[i] + 1);
                y_min_idx = y_min_idx * 2 + 1;
            } else {
                // continue go left
                y_min -= (height[i] + 1);
                y_min_idx = y_min_idx * 2;
            }
        }

        x += (height[i] + 1);
    }
    printf("%d\n", ans);
}

void solve(){
    int i;

    memset(height, 0, sizeof(height));

    // calculate layer step
    if(n > 1)
        height[n-1] = 1;

    if(n > 2)
        height[n-2] = 2;

    for(i = n-3; i >= 1; i--){

        // for(int j = n-1; j > i; j--){
        //  height[i] += (height[j] + 1);
        // }
        height[i] = height[i+1] * 2 + 1;
    }


    for(int i = 0; i < m; i++){
        cal(x1[i], y1[i], x2[i], y2[i]);
    }

}

int main(int argc, char const *argv[])
{
    int i;
#ifndef ONLINE_JUDGE
    freopen("out", "r", stdin);
#endif
    scanf("%d %d", &n, &m);
    for(i = 0; i < m; i++){
        // cin >> x1[i] >> y1[i] >> x2[i] >> y2[i];
        scanf("%d %d %d %d", &x1[i], &y1[i], &x2[i], &y2[i]);
    }
    solve();
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值