<think>
首先,用户的问题是关于计算一个具有n个节点的二叉树在第m层最多有多少个节点的算法。输入格式是:第一行是T,表示测试数据的组数,然后是T行,每行有两个整数n和m。根节点是第0层。输出每个测试用例的第m层最多节点个数。
关键点:
- 我们需要找到第m层的最大可能节点数。
- 这涉及到二叉树的结构,特别是完全二叉树或满二叉树,因为它们可以最大化节点数在特定层。
在二叉树中,第m层的最大节点数是 \(2^m\),因为在一个完全二叉树中,每一层都尽可能填满,直到最后一层。但在一个总节点数为n的二叉树中,第m层的最大节点数受限于n和m。
回忆二叉树的性质:
- 第i层最多有 \(2^i\) 个节点(i从0开始)。
- 深度为k的二叉树最多有 \(2^{k+1} - 1\) 个节点(因为根是深度0)。
对于第m层,最大节点数是 \(2^m\),但前提是该层存在且节点数足够。
然而,如果n很小,可能达不到 \(2^m\) 个节点。例如,如果m很大,但n很小,第m层可能没有节点。
所以,我们需要考虑两种情况:
1. 如果n不足以到达第m层,那么第m层节点数为0。
2. 否则,第m层最多有 min(\(2^m\), 剩余的节点数) 个节点。
但更精确地说,我们需要计算从根到第m-1层所需的节点数,然后剩余的节点可以分配到第m层。
在二叉树中:
- 深度从0到k-1的层最多有 \(2^k - 1\) 个节点。
- 深度k的最大节点数是 \(2^k\)。
但这里m是层数,从0开始。
所以:
- 前m层(从0到m-1)最多需要 \(2^m - 1\) 个节点。
- 证明:前m层节点数最大是 \(\sum_{i=0}^{m-1} 2^i = 2^m - 1\)。
然后,总节点n中减去前m层所需的节点数,剩下的节点可以放在第m层。
但第m层最多可以容纳 \(2^m\) 个节点。
所以:
让 min_nodes_before = \(2^m - 1\) // 前m层最小需要的节点数来支持第m层?不,是最大可能节点数。
为了第m层存在,n必须至少为 min_nodes_before + 1,因为至少有一个节点在第m层。
但为了最大化第m层节点数,我们假设前m-1层是满的,这样第m层可以有尽可能多的节点。
设 full_nodes_before = \(2^m - 1\) // 深度从0到m-1的节点总数,如果满。
如果 n <= full_nodes_before,那么第m层没有节点,输出0。
否则,剩余的节点是 remaining = n - full_nodes_before。
第m层最多可以容纳 max_at_level = \(2^m\) 个节点。
所以,第m层最多有 min(remaining, max_at_level) 个节点。
但 remaining 是剩余节点数,这些节点可以放在第m层,但不超过第m层的容量 \(2^m\)。
是的,所以公式是:
如果 n <= \(2^m - 1\),则 max_nodes_at_m = 0
否则 max_nodes_at_m = min( n - (2^m - 1) , 2^m )
在计算时,\(2^m\) 可能很大,但n和m是输入,我们需要处理可能的边界。
例如:
- n=1, m=0: 前0层节点数?层0是根。full_nodes_before = 2^0 - 1 = 0?等一下。
定义清楚:
- m 是目标层,从0开始。
- 前m层:包括层0到层m-1?不,层是从0到depth。
前k层(层0到k-1)有最多 \(\sum_{i=0}^{k-1} 2^i = 2^k - 1\) 个节点。
对于第m层,为了它存在,节点必须足够覆盖到第m层。
节点数到第m层(包括m层)的最大值是 \(\sum_{i=0}^{m} 2^i = 2^{m+1} - 1\)。
但为了最大化第m层节点数,我们最小化前m-1层的节点数,但为了支持第m层,前m-1层必须至少有一些节点。
在完全二叉树中,为了最大化第m层节点数,我们让前m-1层尽可能少,但又能支持第m层满。
实际上,为了第m层有节点,前m-1层必须有足够的节点来形成路径。
但最小节点数前m-1层是m,因为每层至少一个节点(在路径中),但为了最大化第m层,我们假设前m-1层是满的,这样第m层可以容纳更多节点。
是的,标准方法是:前m-1层(层0到m-2)满时,有 \(2^{m-1} - 1\) 个节点?等一下。
设:
- 层0:1 节点
- 层1:2 节点
- ...
- 层 m-1: \(2^{m-1}\) 节点?不。
层索引 i 有最多 \(2^i\) 节点。
所以,从层0到层 k-1 有最多 \(\sum_{i=0}^{k-1} 2^i = 2^k - 1\) 个节点。
对于第m层:
- 前m层(层0到m-1)有最多 \(2^m - 1\) 个节点。
- 第m层本身最多有 \(2^m\) 个节点。
但当我们说“前m层”,通常包括层0到m-1。
在我们的案例中:
- 让 k = m // 目标层
- 节点用于层0到k-1:最多 full_nodes_before_k = \(2^k - 1\) // 这覆盖层0到k-1
然后,对于第k层,如果 n <= full_nodes_before_k,那么第k层没有节点。
否则,剩余的节点 remaining = n - full_nodes_before_k 可以分配到第k层,但第k层最多容纳 \(2^k\) 节点,所以 max_at_k = min(remaining, \(2^k\) )
在公式中,k 是 m。
所以:
full_before = (1 << m) - 1 // 计算 2^m - 1,使用位运算避免溢出?但在代码中,我们需要处理大数?用户没说范围,但假设在int范围内。
如果 n <= full_before:
result = 0
否则:
remaining = n - full_before
max_at_level = 1 << m // 2^m
result = min(remaining, max_at_level)
但等一下,full_before 是层0到m-1的节点数,对于第m层,我们需要确保前m层足以支持第m层。
在上面的逻辑中,如果 n <= full_before,它意味着所有 n 个节点都在第0到m-1层,所以第m层为0。
如果 n > full_before,那么有节点在第m层或更高,但当我们在第m层放节点时,它们最多可以放 \(2^m\) 个,但 remaining 可能包括更高层的节点,但为了最大化第m层,我们应尽可能多地将节点放在第m层,而不放更高层,因为更高层对第m层计数无贡献。
在二叉树中,为了最大化第m层节点数,我们应该让树尽可能浅,但前m-1层满,然后第m层放尽可能多节点,不留更高层。
是的,因为如果放更高层,那些节点会占用额外空间,但不增加第m层节点数。所以,最优是前m-1层满,然后第m层放 min(remaining, 2^m) 节点,剩余节点忽略或假设不放,但为了最大第m层,我们只放第m层,不放更高。
在计算 remaining = n - full_before,然后 min(remaining, 2^m) 就是第m层最大节点数,因为剩余节点可以全放第m层,如果空间允许。
但第m层最多容纳 2^m 节点,所以是的。
例子:
假设 n=7, m=1
full_before = 2^1 - 1 = 2-1=1 // 层0的节点
remaining =7-1=6
max_at_level =2^1=2
所以 min(6,2)=2
对于m=1,第1层最多2节点,总节点7:层0:1,层1:2,层2:4,但第1层最多2,正确。
另一个例子:n=3, m=1
full_before=1
remaining=3-1=2
min(2,2)=2
树可以是根和两个子节点。
n=3, m=0
full_before for m=0: 2^0 -1 =1-1=0? 等一下。
问题:当 m=0。
对于 m=0,第0层。
前m层:对于 m=0,前0层是层0之前?没有层。
full_before = 2^m -1 = 2^0 -1 =0
如果 n <=0,但n至少1吧?输入n节点。
如果 n <= full_before =0, 但 n>=1, 所以 n>0, 因此 remaining=n-0=n
max_at_level=2^0=1
result=min(n,1)
所以对于 m=0,总是1,如果n>=1。
正确,根节点。
另一个边界:n=1,m=1
full_before=2^1 -1=1
n=1 <=1, so result=0
是的,第1层没有节点。
n=1,m=0: full_before=0, n>0, remaining=1, min(1,1)=1
好。
另一个例子:n=5, m=1
full_before=1 (层0)
remaining=4
max_at_level=2
result=min(4,2)=2
树:层0:1,层1:2节点,层2:2节点(如果完全),但第1层最多2。
n=5, m=2
first, full_before for m=2: 2^2 -1=4-1=3? 层0到1:最多3节点(层0:1,层1:2)
full_before = 2^m -1, for m=2, 2^2 -1=3
如果 n<=3, result=0 for m=2
但 n=5>3, so remaining=5-3=2
max_at_level=2^2=4
min(2,4)=2
所以第2层最多2节点。
在完全二叉树中,它可以是层0:1,层1:2,层2:2(左两个孩子或右两个孩子),是的。
如果放更多在层2,但n=5,只能放2在层2,如果层1满。
max是2。
另一个例子:n=10, m=2
full_before=2^2 -1=3
remaining=7
max_at_level=4
result=min(7,4)=4
所以第2层最多4节点。
n=10, 深度3: 层0:1,层1:2,层2:4,层3:3, 但第2层有4个。
是的。
如果 m 很大,例如 n=10, m=4
full_before=2^4 -1=15
n=10<15, 所以 result=0
因为第4层不存在。
好。
但在公式中,2^m 可能很大,如果 m 很大,但在编程中,我们需要处理。
在输入中,m 可能达到,例如,在二叉树中,深度最多是 n,但 2^m 可能指数增长。
在代码中,如果 m 很大,比如 m>=31 或 63,取决于整数大小,2^m 会溢出。
但用户没有指定范围,所以我们需要处理边界。
在问题中,输出是节点个数,所以如果 m 很大,且 n 小,输出 0。
在计算 full_before = 2^m -1,如果 m 很大,2^m -1 可能溢出。
例如,在 C++ 中,int 是 32 位,2^31 是 2147483648,所以对于 m>30,可能会溢出。
但我们需要处理溢出情况。
同样,在输出中,结果是整数。
策略:
- 如果 m 很大,比如 m > 31(对于 int),那么 2^m 很大,但既然 n 是有限的,很可能 n < 2^m -1,所以 result=0。
但在计算中,我们不能直接计算 2^m 如果 m 很大。
所以,我们需要聪明地处理。
情况:
1. 如果 m == 0,那么最多节点数:如果 n >= 1,则为 1,否则为 0。但 n 是节点数,可能 n >= 1,但输入 n 可能为 0?题目说的是具有 n 个节点的二叉树,所以可能 n >= 1,但为安全起见,检查 n。
输入:每行有 n 和 m,可能 n >= 1,m >= 0。
但为安全起见,在代码中处理。
对于 m=0:结果应为 min(n, 1)
但根据公式,full_before = 2^0 -1 = 0,剩余 = n,max_at_level = 1,最小值为 min(n,1),所以如果 n=0,结果为 0,否则为 1。但可能 n >= 1。
类似地,对于 m>=1。
处理大 m 的方法:
如果 m 很大,例如 m > 100,但 n 是有限的,比如 n <= 10^6,那么对于 m 满足 2^m > n + 某个值,但 full_before = 2^m -1,因此如果 2^m > n,那么 n <= full_before 仅当 2^m -1 >= n,但由于 2^m 很大,成立。
实际上,对于给定的 n,树的最大深度大约是 floor(log2(n)) + 某些值,但粗略来说深度 d 满足 2^d <= n < 2^{d+1},大致如此。
所以如果 m > floor(log2(n)) + 1,那么第 m 层可能不存在。
更精确地说,具有 n 个节点的二叉树的最小深度是当树是平衡树时为 floor(log2(n)),但最大深度是 n(退化)。
但第 m 层存在的条件是深度至少为 m。
深度至少为 m 的最小 n 是 m+1(线性树),但为了最大化第 m 层的节点数,我们需要考虑在可能的情况下填满该层。
在算法中,我们可以这样处理:
- 如果 m 非常大,比如 m > 1000 或 m > 60(对于 64 位),那么如果 n <= 2^m -1,但如果不计算 2^m,我们如何知道?
注意到当 m 很大时,2^m 增长非常快。
我们可以找到最大可能的 m,使得树至少有深度 m。
但具有 n 个节点的树的最大深度是 n(链),所以如果 m <= n,第 m 层可能存在,但节点的数量可能很少。
但我们的目标是该层的最大节点数。
为了计算,我们需要计算 full_before = 2^m -1。
在代码中,我们可以使用位操作,但需要处理溢出情况。
由于输出最多为 n,并且 n 是整数,我们可以处理如下:
- 如果 m 很小,就计算 2^m。
- 如果 m 很大,那么 2^m -1 很大,因此如果 n < 2^m,但等等。
实际上,对于 m 满足 2^m > n(大约),但需要准确。
由于 2^m 呈指数增长,而 n 是有限的,对于给定的 n,存在一个最大 m,使得 2^m <= n + full_before 或类似的条件。
但更容易注意到:如果 m > 0 且 2^{m-1} > n / 2 或类似的条件。
但也许在代码中,我们可以使用对数,但整数运算更好。
一个更好的方法:如果 m 很大,使得 2^m > INT_MAX,但由于 full_before = 2^m -1,如果 m 很大,它将会溢出。
所以,在代码中,我们需要在计算之前检查 m 是否太大。
例如,在 C++ 中,对于 int n,如果 m > 30,那么 2^m > 2^31,因此对于有符号 int 来说,2^m -1 是负数?如果 m>31,2^31 是 2147483648,对于 int 是负数,但由于 n 是正数,n <= full_before 可能为假,但其实对于大的 m,n <= full_before 应该为真。
问题:溢出。
如果 m 很大,2^m -1 溢出为负数,而 n 是正数,因此 n <= full_before(负数)为假,那么我们会进入 else 分支,但 remaining = n - full_before 会变成一个很大的正数,并且 min(remaining, 2^m) 也是错的。
所以要处理溢出情况。
方法:
首先,检查是否 m 非常大,比如 m > 60,那么由于 n 是有限的,第 m 层不可能有节点,输出 0。
但 m 和 n 是输入,所以我们需要找出何时该层不存在。
第 m 层存在的必要条件是树的最大深度至少为 m。
具有 n 个节点的树的最小最大深度是 ceil(log2(n+1)) 或类似的值,但最大深度最多为 n。
但最大深度至少为 m 的条件是 n >= m+1(对于线性树)。
但为了最大化第 m 层的节点数,我们需要前 m-1 层是满的,所以如果 n < 2^{m-1},那么甚至无法填满前 m-1 层,但在我们的公式中,full_before 是针对前 m 层?等等。
回顾一下。
在我们的公式中:
full_before = 2^m - 1 // 第 0 层到第 m-1 层的最大节点数?对于第 m 层,full_before 是第 0 层到第 m-1 层的节点数。
第 0 层到第 m-1 层:最多节点数为 full_before = 2^m - 1
如果 n <= full_before,则第 m 层没有节点,输出 0。
否则,第 m 层最多可以有 min(n - full_before, 2^m)
现在,full_before = 2^m - 1
如果 m 很大,2^m -1 可能溢出。
但我们可以这样计算:如果 m 很大,2^m > n + 2^m -1 之类的,但不行。
注意到对于 m >= 1,(2^m - 1) >= m * 2 或类似的,但更简单的做法是:如果 m 很大,2^m -1 很大,因此对于固定的 n,存在某个 M,使得当 m > M 时,n <= 2^m -1。
例如,2^m -1 >= n 当且仅当 2^m >= n+1。
所以,如果 2^m >= n+1,那么如果 n <= 2^m -1,但 2^m >= n+1 意味着 2^m -1 >= n,是的,所以 n <= 2^m -1。
反过来,如果 2^m < n+1,那么可能 n > 2^m -1,但也可能 n <= 2^m -1。
但 2^m < n+1 并不意味着 n > 2^m -1;例如,n=3,m=1:2^1=2 < 4,但 2^1 -1=1,n=3>1。
但 2^m < n+1 并不直接相关。
在代码中,我们可以检查是否 m 太大,以至于 2^m > MAX_N 或类似的情况。
但 MAX_N 未给出。
由于输出是节点数,并且对于大的 m,输出为 0,所以我们可以这样处理:
- 如果 m == 0,则返回 min(n, 1)
- 否则,如果 m 很大,比如 m > 31,那么检查 n 是否小于 2^{m},但无需计算。
更简单的方法:计算前 m 层所需的最小节点数,但那只是 m+1(对于线性树),但为了最大值,情况不同。
对于大的 m,如果 n <= 2^m -1,则输出为 0,但如果不计算,我们如何知道?
由于 2^m 增长快,在代码中,我们可以使用对数:如果 m > floor(log2(n)) + 1,但 log2(n) 可能不是整数。
例如,n=10,log2(10)≈3.32,floor=3,m 最大为深度?具有 n 个节点的满二叉树的深度是 floor(log2(n)),但最大深度是 n-1。
但第 m 层存在的最大深度至少为 m。
为了安全地计算而不溢出:
在代码中,我们可以使用 long long 如果可用的话,但用户没有指定语言,不过在引用中用了 C++,所以也许在 C++ 中使用 long long。
但输入 T 组数据,每组 n 和 m,所以对于每个查询,我们可以这样计算:
- 如果 m == 0:
- result = (n >= 1) ? 1 : 0 // 但可能 n>=1
- 否则如果 m 很大:
- 但需要定义“很大”
更好的办法是处理计算中的溢出。
在 C++ 中,我们可以写:
```cpp
#include <iostream>
#include <climits>
#include <cmath>
using namespace std;
int main() {
int T;
cin >> T;
while (T--) {
int n, m;
cin >> n >> m;
if (m == 0) {
// 第0层,总是1个节点,如果n>=1
cout << (n >= 1 ? 1 : 0) << endl;
} else if (m < 0) {
// 无效,但假设 m>=0
cout << 0 << endl;
} else {
// 检查 m 是否太大
if (m > 60) { // 假设 n 不大时,对于 m>60,2^m 很大
cout << 0 << endl;
} else {
// 计算 full_before = 2^m - 1
long long full_before = (1LL << m) - 1; // 使用 long long 避免溢出
if (n <= full_before) {
cout << 0 << endl;
} else {
long long remaining = n - full_before;
long long max_at_level = 1LL << m; // 2^m
long long result = min(remaining, max_at_level);
cout << result << endl;
}
}
}
}
return 0;
}
```
在这个代码中,对于 m<=60,我们使用 long long 来计算,以避免溢出。对于 m>60,我们输出 0,因为对于 n 合理的情况,2^m 太大了,但 n 可能很大?如果 n 很大,但 m>60,2^60 是巨大的,所以对于现实中的 n,n <= full_before 成立,因此输出 0 是安全的。
例如,2^60 ≈ 1e18,所以如果 n <= 1e9,n < full_before,因此对于 m>60,输出 0。
在题目中,n 的大小没有说明,但可能 n 是合理的,比如最多 1e9 之类的。
在引用中,例如引用[3] 包含 n 和 m,但没有范围。
为安全起见,在代码中使用 long long 并处理 m 较大的情况。
但在输出中,结果是一个整数,可能很小。
另一个方法:如果对于某些 m,2^m - 1 > LLONG_MAX,但在代码中,如果 m 太大,1LL << m 会是未定义行为,所以我们需要在 m 太大时限制它。
在 C++ 中,位操作在 m 大于类型大小时是未定义行为。
所以在代码中,我们需要设定一个最大 m,比如 60 或 62。
对于 m > 60,无论如何输出 0。
类似于输出。
在用户的问题中,输入输出要求是:输入第一行是 T,然后每行是 n 和 m,输出每个用例第 m 层最多节点个数。
在代码中,我们需要输出结果。
现在,在响应中,用户要求提供算法,并且可能需要代码,但指令是回答用户查询,并且用户说“解决”,所以可能提供代码或描述。
用户说:“我想解决关于计算有n个节点的二叉树的第m层至多有多少个节点的算法问题”和“包含输入输出要求”,所以可能要提供代码。
在引用中,有代码示例。
而且,指令中说“生成相关问题”,在末尾。
首先,解决算法。
所以,算法是:
- 对于每个测试用例:
- 如果 m == 0:
- 输出 min(n, 1) # 但由于 n >=1,输出 1(如果 n>0)
- 否则:
- 计算 full_before = (1 << m) - 1,但注意数值范围
- 如果 n <= full_before:
- 输出 0
- 否则:
- 计算 remaining = n - full_before
- max_at_level = 1 << m
- 输出 min(remaining, max_at_level)
数值处理:在代码中使用 long long 并限制 m,比如 m <= 60,或者使用对数,但整数更好。
另一个想法:不计算 2^m,但检查是否 2^m > n,但我们需要 full_before。
因为对于 m > 0,如果 n <= 2^{m-1} -1 或类似情况,但不够直接。
我认为使用 long long 并在代码中处理 m 较大的情况是可行的。
现在,对于响应,由于用户提到了引用,但引用是关于二叉树的,不过这个问题是独立的。
用户引用包括:
- [1] 二叉树属性:层节点数,n0=n2+1,以及完全二叉树示例。
- [2] 和 [3] 关于子树节点计数,但不同的问题。
- [4] 后序遍历查找路径。
- [5] 二叉树深度计算。
但这个问题不同,所以我可以直接解决。
在响应中,应该提供代码或描述。
用户说“解决”,所以可能提供代码。
输入输出格式:输入第一行 T,然后 T 行,每行 n m。
输出每个用例的整数。
在代码中,我将用 C++ 编写,如引用所示。
处理大 m 的情况:设置最大 m 为 62,例如。
在 C++ 中,1LL << m,当 m > 63 时对于 long long 是未定义行为,因此检查 m 是否大于 62。
代码:
```cpp
#include <iostream>
#include <algorithm>
#include <climits>
using namespace std;
int main() {
int T;
cin >> T;
while (T--) {
long long n, m; // 使用 long long 防止 n 很大
cin >> n >> m;
// 如果 m 为负数,无效,设为 0
if (m < 0) {
cout << 0 << endl;
continue;
}
// 对于第 0 层
if (m == 0) {
if (n >= 1) {
cout << 1 << endl;
} else {
cout << 0 << endl;
}
continue;
}
// 检查 m 是否太大,比如 m > 60
if (m > 60) { // 2^60 约为 1e18,对于 long long 是安全的
cout << 0 << endl;
continue;
}
// 计算第 0 层到第 m-1 层的满节点数
long long full_before = (1LL << m) - 1; // 2^m - 1
// 如果 n 小于或等于前 m 层的节点数,则第 m 层没有节点
if (n <= full_before) {
cout << 0 << endl;
} else {
long long remaining = n - full_before;
long long max_at_level = 1LL << m; // 2^m
long long result = min(remaining, max_at_level);
cout << result << endl;
}
}
return 0;
}
```
在这个代码中,我使用了 long long 来表示 n 和 m,但 m 是层数,可能不会太大,不过为了安全起见。
对于大的 m,比如 m>60,输出 0。
对于 m=0,单独处理。
现在,在响应中,我需要说明算法并添加代码。
另外,在末尾生成相关问题。
首先,组织响应。
用户要求中文,所以用中文回复。
结构:
- 解释算法
- 提供代码
- 相关问题
</think>
根据您的问题描述,我将解决计算具有 n 个节点的二叉树在第 m 层最多节点数的算法问题。输入格式为:第一行为整数 T(测试用例组数),接下来每行包含两个整数 n(节点总数)和 m(目标层,根节点为第 0 层)。输出每个测试用例第 m 层的最大节点个数。
### 算法说明
在二叉树中,第 m 层的最大节点数取决于树的结构。为了最大化第 m 层的节点数,树应尽可能接近完全二叉树,即前 m-1 层完全填满(节点数达到最大值),然后第 m 层放置尽可能多的剩余节点:
1. **前 m-1 层的最大节点数**:层 0 到层 m-1 最多可容纳 \(2^m - 1\) 个节点(因为层 i 最多有 \(2^i\) 节点,求和为几何级数)。
2. **第 m 层的容量**:该层最多可容纳 \(2^m\) 个节点。
3. **关键判断**:
- 如果 \(n \leq 2^m - 1\),所有节点都在前 m-1 层或更浅,第 m 层无节点(输出 0)。
- 否则,剩余节点数 \( \text{remaining} = n - (2^m - 1) \) 可分配到第 m 层,但受限于该层容量,因此最大节点数为 \(\min(\text{remaining}, 2^m)\)。
4. **边界处理**:
- 当 \(m = 0\)(根层):输出 1(如果 \(n \geq 1\)),否则 0。
- 当 \(m\) 过大(如 \(m > 60\)):\(2^m\) 可能溢出或 n 无法支持该层,直接输出 0(因为实际节点数不足以覆盖该层)。
5. **数值安全**:在代码中使用 `long long` 防止溢出,并处理大 m 情况。
该算法时间复杂度为 \(O(1)\) 每测试用例,高效可靠。
### 代码实现
以下是 C++ 代码实现,满足输入输出要求。代码使用位运算高效计算 \(2^m\),并处理所有边界情况。
```cpp
#include <iostream>
#include <algorithm>
using namespace std;
int main() {
int T;
cin >> T; // 读取测试用例组数
while (T--) {
long long n, m;
cin >> n >> m; // 读取每组n和m
// 处理m为负或m=0的情况
if (m < 0) {
cout << 0 << endl;
} else if (m == 0) {
// 第0层最多1个节点
cout << (n >= 1 ? 1 : 0) << endl;
} else if (m > 60) {
// m过大时,第m层不可能有节点
cout << 0 << endl;
} else {
// 计算前m层(层0到m-1)最大节点数: 2^m - 1
long long full_before = (1LL << m) - 1;
if (n <= full_before) {
// 节点不足以覆盖到第m层
cout << 0 << endl;
} else {
long long remaining = n - full_before; // 可分配到第m层的节点
long long max_at_level = 1LL << m; // 第m层容量: 2^m
long long result = min(remaining, max_at_level);
cout << result << endl;
}
}
}
return 0;
}
```
### 输入输出示例
**输入示例**:
```
3 // T=3组测试数据
7 1 // n=7, m=1
3 1 // n=3, m=1
10 2 // n=10, m=2
```
**输出示例**:
```
2 // n=7,m=1: 第1层最多2节点 (e.g., 完全二叉树层0:1, 层1:2)
2 // n=3,m=1: 第1层最多2节点 (e.g., 根节点和两个子节点)
4 // n=10,m=2: 第2层最多4节点 (e.g., 层0:1, 层1:2, 层2:4)
```
### 解释
- **示例分析**:
- 对于 `n=7, m=1`:前 m-1 层(层 0)最大节点数为 \(2^1 - 1 = 1\),剩余节点 \(7 - 1 = 6\),第 1 层容量为 \(2^1 = 2\),因此 \(\min(6, 2) = 2\)。
- 其他用例类似计算。
- **边界安全**:代码使用 `long long` 避免溢出,对大 m(如 \(m > 60\))直接输出 0,因为 \(2^{60}\) 巨大(约 \(10^{18}\)),实际 n 无法支持该层节点。
该算法基于二叉树层节点最大化原理,确保结果正确[^1]。