loj#P4011. 「eJOI2023」Tree Search

「eJOI2023」Tree Search

注意事项

在 LibreOJ 上,由于语言限制,目前只支持以下语言的提交:

  • C++(标准为 C++ 11 及以上)

请在提交源代码前添加 #include "stub.h"

题目描述

本题译自 eJOI2023 Problem A. Tree Search

给定一个由 NN 个顶点组成的有根二叉树。顶点从 11NN 编号,根是顶点 11。其他每个顶点在树中都有一个父节点。这是一个二叉树,即每个顶点最多可以是其他两个顶点的父节点。

其中一个顶点是特殊的。你正在试图寻找这个节点。你可以询问以下问题:「特殊顶点是否在顶点 xx 的子树中?」当且仅当从 yy11 的最短路径经过顶点 xx 时,节点 yy 才在顶点 xx 的子树中。注意,顶点 xx 也在自己的子树中。

你最多询问 3535 次。然后你应该给出你的答案。

实现细节

你应该实现以下函数:

int solve(int N, std::vector<int> p)
  • NN:顶点的数量
  • pp 包含恰好 N1N - 1 个元素,描述了一棵树:每个 0iN20 \leq i \leq N - 2,顶点 pip_i(其中 1pii+11 \leq p_i \leq i + 1)是顶点 i+2i + 2 的父节点。
  • pp 中的元素不会出现超过两次
  • 这个函数应该返回特殊顶点的编号
  • 这个函数只被调用一次

你可以调用以下函数:

int ask(int x)
  • xx:顶点的编号
  • 1xN1 \leq x \leq N
  • 如果特殊顶点在 xx 的子树中,则返回 11,否则返回 00

样例

考虑以下调用:

solve(5, [1, 1, 2, 4])

树由边 (1,2),(1,3),(2,4),(4,5)(1,2),(1,3),(2,4),(4,5) 组成。

你的程序调用了

ask(4)

返回了 11。然后你的程序调用了

ask(5)

返回了 00

你的程序得出结论,顶点 44 是特殊的,并返回了 44

评测程序示例

评测程序示例按以下格式读取输入:

  • 11 行:NN
  • 22 行:p0,p1,,pN2p_0, p_1, \ldots , p_{N - 2}

评测程序示例以以下格式输出每个问题:

  • 11 行:? x?\ x

评测程序示例按以下格式读取每个答案:

  • 11 行:! y!\ y

数据范围与提示

对于所有输入数据,满足:

  • 2N1052 \leq N \leq 10^5

详细子任务附加限制及分值如下表所示。

子任务 附加限制 分值
11 N35N\leq 35 2020
22 pi=i+1 (0iN2)p_i = i + 1\ (0 \leq i \leq N - 2) 3030
33 $p_i = \lfloor i/2 \rfloor + 1\ (0 \leq i \leq N - 2)$ 1515
44 无附加限制 3535