题意: 题目中给出画二叉树的画法,然后说以第一层的点为坐标原点,向下为 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×2N−2 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;
}