QOJ.ac

QOJ

Total points: 100

# 3689. 树

Statistics

本题缺少数据。

问题描述

小 Q 手中有一棵二叉树,它有 $n$ 个节点,编号 $1$ 至 $n$。现在,小 Q 给你出了一道难题,题目是让你将这些节点依次删除,并规定你只能删除没有父亲的节点(即删除一个节点前,必须将其祖先全部删除)。而游戏的难点在于,你并不知道这棵树的形态,只能通过以下方式向小 Q 询问,而小 Q 也会诚实地告诉你答案:

询问方式:$p$ 号点和 $q$ 号点的祖先关系。

回答有三种:$p$ 是 $q$ 的祖先;$q$ 是 $p$ 的祖先;以上皆非。

其中,祖先的定义为:一个点 $A$ 到根的简单路径上的所有点(不含 $A$)都是 $A$ 的祖先。

你需要做的,就是通过尽可能少的询问将所有点全部删除。

规则介绍

这是一道交互类型题目,要求选手使用 C++ 语言进行编程。在程序开头,我们已经为你声明了四个函数供你使用,他们分别是:

int size() //返回这棵树的节点数量n``
int type() //返回这棵树的类型(1、2、3,在数据规模中有详细介绍)
int question(int p, int q) //返回p号点和q号点的关系,若返回值为1,表示p是q的祖先,若返回值为-1,表示q是p的祖先,否则返回值为0,特别注意p和q必须为1至n的整数
void submit(x) //删除x号节点,特别注意x必须为1至n的整数

对于前三个函数,你的程序可以调用任意次。而对于第四个函数,你的程序只能调用 $n$ 次,且每个节点必须恰好被删除一次。并且,你的程序要保证每次删除的节点均为没有父亲的节点。

若你的程序满足上述要求并在规定时间内正常结束,系统会统计你的程序使用 question(int p, int q) 函数的次数记作 $yournum$,并与我们提供的五个评分参数 $a_1\geq a_2\geq a_3\geq a_4\geq a_5$ 作比较。若 $yournum \leq a_i$,则你的得分为 $i$ 分,同时满足多个取最高得分。

提示:经测试,question()函数每秒钟大约可调用 $2 \times 10^8$ 次。计算时间复杂度时请考虑此因素。

特别地,你的程序不允许进行任何输入输出操作,否则将按 $0$ 分处理。

样例程序

using namespace std;
int main()
{
    if (size() == 2) //若n=2,以下算法可以通过一次询问保证正确性
    {
        if (question(1, 2) == 1) //询问1和2的祖先关系
        {//若1是2的祖先,则先删1再删2
            submit(1);
            submit(2);
        }
        else
        {//否则先删2再删1
            submit(2);
            submit(1);
        }
  }
    else //若n不为2,则按1~n的顺序删,当然这就不能保证正确性了
        for (int i=1; i<=size(); i++)
            submit(i);
}

数据规模和约定

$n$
数据类型
所占比例
$n$
数据类型
所占比例
$\leq 5\,000$
1
$10\%$
$\leq 300\,000$
1
$10\%$
$\leq 5\,000$
2
$10\%$
$\leq 300\,000$
2
$20\%$
$\leq 5\,000$
3
$25\%$
$\leq 100\,000$
3
$25\%$

数据规模即int size()的返回值,表示这棵树的节点数量。

数据类型即int type()的返回值:

  • 1 表示这棵树为一个“链”,准确地说每个点最多只有一个儿子;
  • 2 表示这棵树为一棵满二叉树;
  • 3 表示我们不知道这棵树有什么特殊形态。

or upload files one by one: