#L3849. 「NOI2022」树上邻域数点
「NOI2022」树上邻域数点
题目描述
给出五元组 ,其中:
- 是一棵 个点的有根树 ,其中 为 的点集, 为 的边集。树的节点被编号为 ,其中根节点编号为 。
- 是一个集合,集合中的元素称作信息。其中有两个不同的特殊元素:单位元 和不合法信息 。
- 对于一般的信息,其都具有点集合和边集合两个属性。特别的,对于单位元,其只有边集合的属性,而对于不合法信息,其没有以上两种属性。
对于信息 , 的点集合是 的一个二元子集,记作 ,满足 且 。其中,两个集合 的差 被定义为 。
对于信息 , 的边集合是 的一个子集,记作 ,满足 。规定单位元的边集合为空,也即 。
对于树上的任何一条边 ,记 ,存在一个关于 的信息 ,它以其端点为点集合、自身为边集合,即 、。
信息有两种合并的方式,分别记作 和 。对于 ,记 ,满足 ,则:
- 单位元和任何信息合并都得到对方。也即,如果 ,那么 ;如果 ,那么 。
- 不合法信息和任何信息合并都得到不合法信息。也即,如果 或者 ,那么 。
- 对于剩下的情况,如果两个信息的边集合的交集非空,或者点集合的交集的大小不为 ,则合并得到不合法信息。也即,如果 或 ,则 。
- 否则,有 [ \begin{aligned} S_E(r) &= S_E(c) = S_E(a) \cup S_E(b), \ S_V(r) &= S_V(a), \ S_V(c) &= S_V(a) \oplus S_V(b), \end{aligned} ] 其中 表示集合的对称差运算,也即 。
定义 中两个点的树上距离为树上以两个点为端点的唯一简单路径经过的边数。
给出评分参数 和 次询问,每次询问给出树上的一个点 和一个非负整数 。记点集 为 中所有与 的树上距离不超过 的点构成的集合,又记边集 为 内部的边集。可以证明,从 和所有 ()出发,总是能通过有限次 的调用得到信息 满足 。
每组询问中,你需要在 和 的调用次数总和不超过 的限制下构造出一个满足这样的要求的信息 。特别地,如果 ,则直接返回单位元 即可。
实现细节
请确保你的程序开头有 #include "count.h"。
头文件 count.h 中实现了如下内容:
- 定义了信息对应的数据类型
info; - 定义了 所对应的
info类型常量emptyinfo,你可以在程序中直接使用。 - 定义并实现了以下两个信息合并函数,你可以在程序中直接调用:
两个函数分别返回 与 对应的信息。info MR(info a, info b); // 返回 R(a, b) info MC(info a, info b); // 返回 C(a, b)
你需要保证调用 与 时结果不为 ,否则程序可能会出现异常行为。 - 定义并实现了判定一个信息是否为单位元的函数,你可以在程序中直接调用:
bool isempty(info a); // 返回真当且仅当 a 为单位元
你不需要,也不应该实现主函数。你需要实现如下几个函数:
void init(int T, int n, int q, vector<int> fa, vector<info> e, int M);
T表示测试点编号,n表示树的点数,q表示询问数,M表示该测试点的评分参数。fa和e的长度均为 。对于 ,fa[i]和 为第 条边 的两个端点,e[i]为题目描述中提到的 所对应的info类型元素。数据保证fa[i]小于 。
info ask(int u, int d);
给出一个询问,参数的意义见题目描述。你需要在函数结束时返回一个满足题设条件的信息。
样例
样例 1
见附件中的 count/count1.in 与 count/count1.ans。
样例 2
见附件中的 count/count2.in 与 count/count2.ans。
该组样例满足数据范围中的特殊性质 A。
样例 3
见附件中的 count/count3.in 与 count/count3.ans。
该组样例满足数据范围中的特殊性质 B。
样例 4
见附件中的 count/count4.in 与 count/count4.ans。
数据范围与提示
对于所有测试点,,;每组询问中,有 ,。

特殊性质 A:保证 ,编号为 的点的父节点为 。
特殊性质 B:保证所有询问均满足 。
特殊性质 C:保证所有询问均满足 。
特殊性质 D:保证所有询问均满足 。