这是一道交互题,只为 C++ 提供接口函数。
Scape 家的后院种了许多二叉树,树上的每个结点最多只有一个父结点、一个左儿子和一个右儿子。作为他家的园丁,你需要帮他维护这些二叉树。
结点有两种状态:正常状态以及枯萎状态。这些二叉树共有 个结点,分别编号为 到 。初始时有 棵二叉树,分别编号为 到 ,二叉树 上只有结点 这一个结点,且所有结点都处于正常状态。
接下来可能发生以下的 3 种事件:
为了对这些树进行调整,你给每棵树分配了两个手下,我们称之为某棵树的 号手下或者 号手下,初始时他们都站在负责的树的唯一一个结点上。每次你可以让某个手下移动到一个相邻的结点,这时你可以命令他把该结点的某个儿子修改为某个结点(原来的儿子的子树会分离出去;新的儿子的父结点也会同时修改为当前结点)。由于某种神秘力量的影响,修改某个结点的儿子后该结点的所有祖先结点(包括自己)都会变为枯萎状态。最后他会给该结点浇上水,如果此时该结点的所有儿子(忽略空儿子)都处于正常状态的话,这个结点就会变为正常状态。
简要题意:要求用二叉树维护若干个序列。交互库会对每棵树提供两个指针,分别指向树上的某个结点。允许修改某个指针指向结点的儿子、更新某个指针指向结点的子树信息和以及把某个指针移动到相邻结点。需要通过这些指针完成合并、分裂、查询操作。
你需要实现以下的四个函数:
init(n, maxdep, maxcnt)
join(x, y, &id1, &id2)
split(x, k, &p1, &p2, &p3, &p4)
visit(x)
你可以调用 move()
来指挥你的手下,但是该函数的总调用次数不能超过 次,并且在每次事件中(即交互库调用 join()/split()/visit()
函数到该函数结束的这段时间内)move()
函数的调用次数不能超过 。
move(k, id, x, c, y)
你只能提交一个源文件实现上述的函数,并且遵循下面的命名和接口。源代码中需要包含头文件 tree.h
。
void init(int n, int maxdep, int maxcnt);
void join(int x, int y, int &id1, int &id2);
void split(int x, int k, int &p1, int &p2, int &p3, int &p4);
int visit(int x);
void move(int k, int id, int x, int c, int y);
下发文件中附有样例程序。
交互库将读入如下格式的输入数据:
第一行为四个整数 , 表示事件的个数。读入此行后交互库会调用一次 init()
函数。
接下来 行,每行描述一次事件。若为事件 join,输入三个整数 1 x y
;若为事件 split,输入三个整数 2 x k
;若为事件 visit,输入两个整数 3 x
。读入每行后交互库会调用对应的函数。
交互库会在每次调用 visit()
函数后进行某些输出,如果输出与数据的输出文件一致且 move()
函数的调用次数未超过上限,则视为通过该测试点。如果你在调用 move()
函数时传入了非法的参数或者返回值不合法,交互库会马上退出。
通过访问输入输出文件、攻击评测系统或攻击评测库等方式所得分数无效。
C++ 以外的语言可以通过标准输入输出进行交互。
程序开始时,从标准输入读入一行,包含三个空格分隔的正整数 。
此后,从输入不断读入格式如下的信息:
J <x> <y>
:表示一次 join 事件。向标准输出输出一行 1 <id1> <id2>
并刷新输出缓冲(例如 Pascal 语言的 flush(output)
和 Java 语言的 System.out.flush()
,其他语言请参阅语言文档),所有值的含义如上所述。S <x> <k>
:表示一次 split 事件。向标准输出输出一行 1 <p1> <p2> <p3> <p4>
并刷新输出缓冲。V <x>
:表示一次 visit 事件。向标准输出输出一行 1 <root>
并刷新输出缓冲。其中 <root>
为调整过后树的根结点编号,相当于 visit()
的返回值。F
:结束程序。其中任何时刻需要调用 move()
时,向标准输出输出一行 0 <k> <id> <x> <c> <y>
并刷新输出缓冲。
所有输出同样需要满足上述限制。
请下载「附加文件」。
请注意最终测评使用的 tree.h
与下发的文件并不一致。
由于交互量较大,时限放宽至标程在 LOJ 上运行耗时的两倍。