#CF1990E2. Catch the Mole(Hard Version)

    ID: 6909 交互题 8000ms 256MiB 尝试: 1 已通过: 1 难度: 10 上传者: 标签>数据结构搜索搜索与剪枝其他二分查找树结构分治*2600

Catch the Mole(Hard Version)

CF1990E2 Catch the Mole(Hard Version)

题目描述

这是该问题的困难版本,唯一的区别在于查询次数的限制。

这是一个交互式问题。

给定一棵有 nn 个节点的树,节点 11 为根节点。

有一只“鼹鼠”藏在某个节点上。为了找到它的位置,你可以选择一个整数 xx1xn1 \le x \le n)向评测机发起一次询问。接下来,评测机会返回 11,如果鼹鼠在以 xx 为根的子树中;否则,评测机会返回 00。如果评测机返回 00 且鼹鼠当前不在根节点 11,那么鼹鼠会移动到它当前所在节点的父节点。

请在最多 160160 次操作内,找出鼹鼠当前所在的节点。

输入格式

每个测试包含多组测试用例。第一行包含测试用例数 tt1t1001 \le t \le 100)。接下来是每组测试用例的描述。

输出格式

每组测试用例的第一行包含一个整数 nn2n50002 \le n \le 5000)。

接下来的 n1n-1 行描述树的边。每行包含两个用空格分隔的整数 uiu_iviv_i1ui,vin1 \le u_i, v_i \le n),表示节点 uiu_iviv_i 之间有一条边。

保证输入数据构成一棵树。

本题的交互器是非自适应的。也就是说,鼹鼠最初所在的节点在每个测试用例中是固定的,在交互过程中不会改变。

你可以选择一个顶点 xx1xn1 \le x \le n)进行一次询问,输出如下格式的一行:

  • "? x"

之后,你会收到:

  • 00,如果鼹鼠不在以 xx 为根的子树中;
  • 11,如果鼹鼠在以 xx 为根的子树中。

每个测试用例最多可以进行 160160 次此类询问。

接下来,如果你的程序已经找到了鼹鼠当前所在的节点,输出如下格式的一行:

  • "! x"

注意,这一行不计入查询次数。

输出每次查询或每组测试用例的答案后,不要忘记输出换行并刷新输出缓冲区。否则会收到 Idleness Limit Exceeded 的判定。具体操作如下:

  • C++:fflush(stdout) 或 cout.flush()
  • Java:System.out.flush()
  • Pascal:flush(output)
  • Python:stdout.flush()
  • 其他语言请参考相关文档。

Hack 数据

Hack 时请按照如下格式:

第一行包含测试用例数 tt1t1001 \le t \le 100)。接下来是每组测试用例的描述。

每组测试用例的第一行包含两个整数 nnxx2n50002 \le n \le 50001xn1 \le x \le n),分别表示树的大小和鼹鼠的初始位置。

接下来的 n1n-1 行描述树的边。每行包含两个用空格分隔的整数 uiu_iviv_i1ui,vin1 \le u_i, v_i \le n),表示节点 uiu_iviv_i 之间有一条边。

输入数据必须构成一棵树。

输入输出样例 #1

输入 #1

2
2
1 2

1

6
1 2
1 3
1 4
4 5
5 6

0

0

1

输出 #1

? 2

! 2






? 2

? 6

? 4

! 4

说明/提示

在第一个测试用例中,鼹鼠最初在节点 22

对于查询 "? 2",评测机返回 11,因为鼹鼠在以 22 为根的子树中。此时鼹鼠不会移动。

答案 22 即为鼹鼠当前所在的节点,因此答案是正确的。

在第二个测试用例中,鼹鼠最初在节点 66

对于查询 "? 2",评测机返回 00,因为鼹鼠不在以 22 为根的子树中。此时鼹鼠从节点 66 移动到节点 55

对于查询 "? 6",评测机返回 00,因为鼹鼠不在以 66 为根的子树中。此时鼹鼠从节点 55 移动到节点 44

对于查询 "? 4",评测机返回 11,因为鼹鼠在以 44 为根的子树中。此时鼹鼠不会移动。

答案 44 即为鼹鼠当前所在的节点,因此答案是正确的。

请注意,示例仅用于帮助理解题意,示例中的查询并不保证能唯一确定鼹鼠的位置。

由 ChatGPT 4.1 翻译