给定一棵包含 $n$ 个顶点的树。树是一个图,其中每两个顶点之间恰好有一条简单路径。此外,保证至少有一个顶点直接与至少 3 个顶点相连。其中一个顶点是根,你的任务是找到它。为了做到这一点,你可以进行以下形式的询问:
- 对于给定的顶点集合 $a_1, a_2, \dots, a_m$,检查它们的最近公共祖先(LCA)是否在该集合中。
如果从集合 $S$ 中所有顶点到根的路径都经过顶点 $v$,则称 $v$ 是集合 $S$ 的公共祖先。集合 $S$ 的最近公共祖先(LCA)是 $S$ 的所有公共祖先中距离根最远的一个。
交互
首先读取一个整数 $n$ ($4 \le n \le 500$),表示顶点数。
然后读取接下来的 $n - 1$ 行。第 $i$ 行包含两个整数 $a_i, b_i$ ($1 \le a_i, b_i \le n$),表示树中顶点 $a_i$ 和 $b_i$ 之间有一条边。
保证这 $n - 1$ 条边构成一棵树,且至少有一个顶点直接与至少 3 个顶点相连。
进行询问时,首先输出 ?,然后输出整数 $m$,接着输出 $m$ 个不同的整数 $a_1, a_2, \dots, a_m$ ($1 \le m \le n, 1 \le a_i \le n$,所有 $a_i$ 互不相同) —— 即你想要检查其 LCA 是否在其中的顶点集合。
作为响应,交互器将输出 YES(如果它们的 LCA 是 $a_1, a_2, \dots, a_m$ 中的一个)或 NO(否则)。
你最多可以进行 1000 次询问,但根据你使用的询问次数,你将获得不同数量的分数。输出答案不计入询问次数。请查看子任务部分了解详情。
当你确定了根节点后,输出符号 !,然后输出一个整数 $v$ ($1 \le v \le n$) —— 即根节点。然后终止你的程序。
在打印询问后,不要忘记输出换行并刷新输出。为此,请使用:
C++ 中的 fflush(stdout) 或 cout.flush();
Python 中的 stdout.flush();
保证对于每个测试用例,树及其根在交互开始前就已经固定。换句话说,交互器不是自适应的。
样例
输入 1
7 4 1 1 2 4 3 3 5 3 6 4 7
输出 1
? 2 5 6
输入 2
NO
输出 2
? 3 6 3 5
输入 3
YES
输出 3
? 2 1 7
输入 4
NO
输出 4
? 2 4 6
输入 5
YES
输出 5
! 4
说明
隐藏的根是顶点 4。
在第一次询问中,顶点 5 和 6 的 LCA 是顶点 3,它不在顶点 5 和 6 中,所以答案是 NO。
在第二次询问中,顶点 3、5 和 6 的 LCA 是顶点 3,所以答案是 YES。
在第三次询问中,顶点 1 和 7 的 LCA 是顶点 4,所以答案是 NO。
在第四次询问中,顶点 4 和 6 的 LCA 是顶点 4,所以答案是 YES。
在此之后,我们可以猜出根是顶点 4,这是正确答案。
子任务
- (7 分): $n \le 9$
- (10 分): $n \le 30$
- (最高 83 分): $n \le 500$
在第一个和第二个子任务中,你最多可以进行 1000 次询问。
在第三个子任务中,设 $k$ 为你在任何测试中使用的最大询问次数。如果 $k \le 9$,你将获得 83 分。否则,你将获得 $\lfloor \max(10, 83 \cdot (1 - \frac{\ln(k-6)}{7})) \rfloor$ 分。
计算第三个子任务分数的 C++ 代码如下:
((k <= 9) ? 83: max(10, int(83 * (1 - log(k - 6.0) / 7))))