题目:

小红有一棵以 1 号节点为根的完全二叉树(节点 i 的左儿子为 2i、右儿子为 2i+1),给定 n 个节点和 q 次询问,每次查询一个节点 x,需要求出与 x 节点深度相同的节点总数(包含 x 自身)。

核心思路:

步骤 1:确定查询节点 m 的深度对应的区间 在完全二叉树中,深度为 d 的节点,编号范围是 [2^(d-1), 2^d - 1](比如深度 1:[1,1],深度 2:[2,3],深度 3:[4,7],深度 4:[8,15]...); 代码中用 temp 从 1 开始倍增(temp2),直到 temp2 > m,此时 temp 就是当前深度的起始编号(即 2^(d-1)),k 最终等于 d-1(比如 m=5,temp 最终是 4,k=2,对应深度 d=3)。

步骤 2:计算该深度的节点总数 理论上,深度 d 的节点总数是 2^(d-1)(即代码中的 pow(k)),但如果是最后一层(节点总数 n 小于该层的最大编号 2^d -1),则实际节点数需要按 n 截断;

公式:min(n, 2^d -1) - 2^(d-1) + 1(min(n, 2^d -1) 是该层实际最大节点号,减起始号加 1 就是节点总数)。

建议: pow() 函数,手动实现 2 的 k 次方(避免使用库函数 pow 的浮点误差)。别问为什么,本人就因这个卡了半天。

#include<bits/stdc++.h>
using namespace std;
inline void optimizeIO() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr);
	cout.tie(nullptr);
}

long long pow(int y) {
	long long res=1;
	for (int i=0;i<y;i++) {
		res *= 2;
	}
	return res;
}

int main() {
	optimizeIO();
	int t;
	cin >> t;
	while (t--) {
		long long n, q;
		cin >> n >> q;
		while(q--){
			long long m;
			cin >> m;
			long long temp=1;
			int k=0;
			while(temp*2<=m)
			{
				temp*=2;
				k++;
			}
			long long a, b;
			a = pow(k);
			b = pow(k + 1) -1;
			cout << min(n,b) - a + 1 << endl;
		}
	}
	return 0;
}