[CEOI2023] The Ties That Guide Us (incursion)

题目描述

你用销售机器人的利润雇佣了一名助手,现在你准备好去拿走装有 CEOI 奖章的保险箱了。 保险箱位于一所由 $n$ 个房间所组成的大学建筑内,这些房间由 $n-1$ 扇门连接。每个房间都可以从其他任何房间到达,且每个房间最多与 $3$ 扇门相连。 你和你的助手都有描述建筑物内房间相连情况的平面图,但是你们两个各自拥有的平面图虽然描述了相同的房间结构布局,但是房间和门的编号可能不同。 在比赛的第二天,委员会忙于处理赛时通知和选手提问。这将是接近装着奖牌的保险箱的完美机会。 你的助手会首先搜索整栋大楼。一旦他找到保险箱所在的房间,它就会给你留下前往那个房间的提示。由于手机不能带进赛场,他用了去年 BOI 留下的几乎无限供应的领带。由于这些领带完全相同无法区分,你能获得的信息就是他在任何给定房间里所留下的领带数量。由于一个房间内过多的领带非常可疑,因此任何单个房间内领带的最大数量应当尽可能少(参阅评分部分)。 之后,你计划在上厕所的时候溜出去,利用助手留下来的领带找到有保险箱的房间。保险箱藏在房间里,所以你进入带有保险箱的房间时,必须依靠领带识别这个房间;此外,由于“上厕所”时间过长会被发现,你必须尽快找到保险箱。你最多可以走过 $d+30$ 扇门,其中 $d$ 是你的初始位置到保险箱所在位置的最短路径上的门数量。若重复穿过同一扇门,则每次都计入。 因此,你需要编写一个程序,告诉助手需要在每个房间留下多少条领带,并引导你前往带有保险箱的房间。

输入输出格式

输入格式


本题为函数交互题。 对于每个测试点,你的程序会运行两次。 你需要实现如下两个函数(函数原型已给出): ``` vector<int> mark(vector<pair<int,int>> F, int safe); ``` - $F$: 包含了 $n-1$ 个二元组 $(u,v)$,其中 $1 \le u,v \le n$ 并且保证 $u \neq v$,代表在助手的地图上,$u$ 号房间和 $v$号房间之间由一扇门相连。 - $\mathrm{safe}$: 表示你的助手的地图上保险箱所在的房间编号。 该函数应当返回一个长度为 $n$ 的 `vector<int>` $v$,其中每个元素 $v_i$ 代表你的助手应当在他地图上 $i+1$ 号房间留下的领带数量。你应当保证 $0 \le v_i \le 10^9$。 ``` void locate(vector<pair<int,int>> F,int curr,int t); ``` - $F$: 包含了 $n-1$ 个二元组 $(u,v)$,其中 $1 \le u,v \le n$ 并且保证 $u \neq v$,代表在你的地图上,$u$ 号房间和 $v$号房间之间由一扇门相连。 - $\mathrm{curr}$: 你目前所在的房间编号。 - $t$: 在你当前所处的房间中,找到的领带数量。 在如下的叙述中,房间编号采用你地图的编号方案。 在实现函数 `locate` 的过程中,你可以调用如下函数: ``` int visit(int v); ``` 以此来从你目前所在的房间 $u$ 移动到一个相邻的房间 $v$。你需要保证操作合法,即 $1 \le v \le n,(u,v) \in F\:\vee (v,u) \in F$。 该函数返回一个非负整数 $k$,表示你在房间 $v$ 中找到的领带个数。 该函数调用的次数不应超过 $d+30$,其中 $d$ 是你的起点到终点的最短距离。 当函数 `locate` 终止时,你应当处于带有保险箱的房间内。 对于每个测试点,第一次运行程序时调用 `mark`,第二次调用 `locate`。 如果 `visit` 调用次数过多、调用不合法或在 `mark` 中被调用,你的程序将会被终止运行,提交将会被判**错误**。 你的程序不得写入或读取 `stdin` 或 `stdout`,否则将会被判**违反安全规定**。 但是你可以随便往 `stderr` 输出,没人管这个。 你需要在源代码文件开头加上 `#include "incursion.h"`。 你应当将程序与 `sample_grader.cpp` 链接以进行本地测试。 下面是示例评分器的说明,请参阅 `sample_grader.cpp` 以获取操作说明。 为简单起见,本评分器不会运行你的程序两次,而是在一次运行中调用两个函数各一次。附件中包含了一个 `sample_grader.cpp` 的示例实现。 注意:该实现不与评测所用的实现相同,禁止采用 Hack 评分器的方式试图通过本题!

输出格式


输入输出样例

暂无测试点

说明

### 评分细则 共有 4 个 subtask。对于每个测试点,$2 \le n \le 45000$。 Subtask 1 (30 points),保证没有一个房间有三扇门相连。 Subtask 2 (30 points). 有且仅有一个房间有两扇门相连。 Subtask 3 (40 points). 没有特殊性质。 对于每个测试点,假设使用领带最多的房间用了 $T_{\max}$ 条领带, - $T_{\max}<2$,你将会获得该测试点 $100\%$ 的分数。 - $T_{\max}=2$,你将会获得该测试点 $40\%$ 的分数。 - $2 < T_{\max} \le 10^9$,你将会获得该测试点 $30\%$ 的分数。 ### 交互库使用方法 **注意洛谷提供的交互库与原版不同。** 请使用 `g++ -std=c++17 -Wall -O2 -o test interactive_lib.cpp xxx.cpp` 编译,其中 `xxx.cpp` 是你的程序名字。 示例交互库首先从标准输入读入三个正整数, $n$, $s$, $seed$,表示点数、起点的原编号、随机数种子。 然后读入 $n-1$ 行,每行两个正整数 $u,v$,表示原树的一条边。其中需保证 $1 \le u < v \le n$。 然后读入一行一个字符串,表示打乱规则。 **你不需要在意打乱序号的具体实现。该实现与最终评测所用交互库不一定相同。** 接下来交互库将会调用一次 `mark`,一次 `locate`。注意交互库可能会打乱序号。 交互库可能向终端输出以下信息: - `Invalid input.` 输入不合法。 - `Invalid call to visit. (ALICE CALLED VISIT)` 在 `mark` 中调用 `visit`。 - `Invalid call to visit. (INDEX ERROR)` 访问了不合法的点。 - `Invalid call to visit. (NOT CONNECTED)` 访问的点和当前所在的点没有直接的边相连。 - `Invalid call to visit. (TOO MANY VISITS)` 调用 `visit` 次数过多。 - `Invalid return value of mark.` `mark` 的返回值不合法。即返回的 `vector` 长度不为 $n$ 或者有小于 $0$ 或大于 $10^9$ 的数。 - `Not correct: current position is X` 最终并不在目标点,你应该在 $X$ 点(在第二张地图上)。 - `Correct: at most X tie(s) per room.` 到达目标点,且用领带最多的房间使用了 X 条领带。 最终评测时,只会返回正确与否的信息。