题目描述
这是一道交互题。
你本来是要去下界堡垒参加猪灵的黄金派对的,但很不幸的是,你迷路了。你现在既不知道自己在哪,也不知道自己要去的下界堡垒在哪。
下界的地形构成了一棵由 $n$ 个点组成的树(树上的点编号为 $1$ 到 $n$)的结构,你现在的位置在点 $a$,你想去的地方为点 $b$。你已经知道了树的结构,但是不知道 $a,b$ 的值。好消息是,你的猪灵朋友将会帮助你找出它们。
首先,你的猪灵朋友会告诉你 $a,b$ 之间的路径上的一个点 $c$。然后你可以进行若干次操作,具体而言,你可以要求他把磁石移动到点 $u$,然后你通过观察指南针就可以知道
- 如果把点 $u$ 看做树的根,那么 $a,b$ 在树上的最近公共祖先是哪个点。
但是,你的猪灵朋友在告诉你 $c$ 之前,想要先知道根据该树形态和你的策略,最坏情况下至少需要搬动磁石的次数 $e$。当然,在你告诉他 $e$ 之后,他就只允许你进行 $e$ 次操作了。
交互方式
你不需要,也不应该实现主函数,你只需要实现函数 void solve(int n, const std::vector<std::pair<int, int>> &E)
,这里的 $n$ 表示树所包含的点数,$E$ 给出了树上有连边的点对,保证 $E$ 的长度为 $n-1$。你可以通过调用如下三个函数来和交互库进行交互:
int set_limit(int e)
:回答最坏情况下至少需要搬动磁石的次数 ,这个函数必须在其他函数之前调用,并且被调用恰好一次。这个函数返回 $a,b$ 之间的路径上的一个点 $c$;int query(int u)
:要求猪灵朋友把磁石移动到点 $u$,返回在树上把点 $u$ 看做树的根时,$a,b$ 在树上的最近公共祖先;void answer(int a, int b)
:回答你的位置和下界堡垒的位置 ,这个函数必须被最后调用,且被调用恰好一次。
约束
对于 $20\%$ 的数据,有 $1\le n\le4$;
对于另外 $30\%$ 的数据,有 $1\le n\le2000$;
对于全部数据,有 $1\le n\le10^5$。
题目保证:
一定有 $a\le b$;
给出的边一定构成一颗树;
评测时,交互库会恰好调用
solve
一次;本题保证所选定的点 $a,b,c$ 在交互开始之前已经完全确定,不会根据和你的程序的交互过程动态构造,因此题目中的交互操作都是确定性的,你不需要关心这些操作在交互库中的具体实现;
在保证询问次数不超过 $n$ 的前提下,交互库所使用的的时间不超过 2 秒,空间不超过 128MiB,也就是说你至少有 2 秒时间和 384MiB 空间可以使用。
你要保证:
在调用
set_limit
函数之前不会调用query
或answer
函数,且传入的参数 $e$ 满足 $0\le e\le n$;调用
query
函数的次数不超过你在调用set_limit
函数时传入的参数 $e$,且传入的参数 $u$ 满足 $1\le u\le n$;调用
answer
之后从solve
函数中立即返回。
评分标准
在答案正确的前提下,若按照你的策略,最坏情况下至少需要搬动磁石的次数为 $e$。按照最优策略,最坏情况下至少需要搬动磁石的次数为 $e'$。令 $\alpha=(e+1)/(e'+1)$,那么:
若 $\alpha<1$,得 $0\%$ 的分数;
若 $\alpha=1$,得 $100\%$ 的分数;
若 $1<\alpha\le1.1$,得 $20\%$ 的分数;
若 $\alpha>1.1$,得 $10\%$ 的分数。
实现细节
下发文件已经提供了一个 sample.cpp
,你可以将这个文件拷贝一份,重命名为 compass.cpp
,然后在其基础上答题。
请确保你的程序开头包含:
#include "compass.h"
试题目录下的 grader.cpp
以及 compass.h
是我们提供的交互库参考实现,最终测试时所用的交互库实现与该参考实现有所不同,因此选手的解法不应该依赖交互库实现。
你需要在本题目录下使用如下命令编译得到可执行程序:
g++ grader.cpp compass.cpp -o compass -O2 -std=c++14
对于编译得到的可执行程序,可执行文件将从标准输入读入以下格式的数据:
第一行一个整数 $n$,然后 $n-1$ 行描述树的结构。最后一行三个数 $a,b,c$。读入完成之后,交互库将调用恰好一次函数 solve
,用输入的数据测试你的函数。你的函数正确返回后,交互库会判断你的计算是否正确,若正确则会输出 OK.
和交互函数调用次数相关信息,否则会输出相应的错误信息。
提示
不保证 $a\not=b$,$a\not=c$,或 $b\not=c$。