1 条题解
-
0
题意重述
我们有一个在区间 上的二叉树(区间树),每个非叶子节点 有一个分割点 (),左孩子 ,右孩子 。
树的结构由先序遍历顺序给出所有非叶子节点的分割点。对于任意询问区间 (),定义时间复杂度为定位该区间时需要访问的节点数。
定位规则:节点 当且仅当:
- 代表的区间是 的子区间,但 的父节点不满足此条件;
- 的后代至少有一个节点满足条件 1。
实际上这与标准线段树查询过程一致:
查询 时,从根开始递归,如果当前节点区间与 无交,则不访问;如果当前节点区间完全包含于 ,则该节点被选中,不递归孩子;否则(相交但不完全包含)访问该节点并递归孩子。
访问节点集合就是所有递归过程中到达的节点(包括最终选中的节点和递归中途访问的节点)。等价地,可以证明:节点 被访问当且仅当 的区间与 相交。
证明“相交 ⇔ 访问”
设节点 区间为 ,查询区间为 。
- 若 ,则不会进入该节点,不访问。
- 若 ,则 被访问(且选中,停止递归)。
- 若 (真子集),则 被访问(递归进入孩子)。
- 若相交但不包含,则 被访问(递归进入某个孩子)。
综上,只要相交就访问。
因此 = 与 相交的节点数。
问题转化
设树的总节点数为 (最多 )。
与 相交的节点数 = − 完全在 左边的节点数 − 完全在 右边的节点数。定义:
- = 右端点 的节点数。
- = 左端点 的节点数。
则:
目标
我们需要对每个 计算满足 的区间 个数,其中 。
由上式:
$$N - A[l] - B[r] = k \quad\Longleftrightarrow\quad A[l] + B[r] = N - k $$记 ,则问题转化为:
$$\text{Count} \{(l, r) \mid 1 \le l \le r \le n,\; A[l] + B[r] = C \} $$
预处理
-
建树:根据先序遍历分割点序列递归构造二叉树,得到每个节点的区间 。
递归函数build(l, r)读取一个分割点 ,创建节点 ,然后递归build(l, m)和build(m+1, r)(如果是叶子则停止)。 总节点数 。 -
计算 和 :
- = 右端点 的节点数,可以对所有节点按右端点排序后前缀和得到。
或者用差分:对节点 ,在 处 +1,然后前缀和得到 表示右端点 的数量。 - = 左端点 的节点数,可以对所有节点按左端点排序后后缀和得到。
或者用差分:对节点 ,在 处 +1(需注意边界),然后后缀和得到 。
更简便方法:
= 右端点 的节点数; = 左端点 的节点数。
可以用两个数组cntR[x]记录右端点 = 的节点数,cntL[x]记录左端点 = 的节点数,然后前缀/后缀和。 - = 右端点 的节点数,可以对所有节点按右端点排序后前缀和得到。
-
枚举所有 并统计 的分布:
直接枚举 不可行。
注意到 只依赖于 , 只依赖于 ,且 ,值域较小()。我们可以对每个 ,需要数出满足 且 的 个数。
做法:- 预先将 按 值分组,每组存储所有 并排序。
- 对每个 ,设 ,在 对应的列表中二分查找 的 个数,累加。
这样总复杂度 ,可接受。
回答询问
由于 ,但实际 ,因此:
- 若 或 ,答案为 。
- 否则 在 内,输出上一步统计的 ( 表示 的区间 个数)。
样例推导
样例输入:
6 7 5 1 3 2 4 1 2 3 4 5 6 7先序遍历分割点构造树(见之前的树结构),总节点数 (包括叶子)。
计算 (过程略),然后统计 ,得到:
,输出
,输出
,输出
,输出
,输出
,输出
,输出与样例输出一致。
算法步骤总结
-
建树:递归读取分割点,构造二叉树,记录每个节点的区间 。
-
计算 :
- 初始化
cntR[0..n+1]=0。 - 对每个节点 ,
cntR[R]++。 - 前缀和:
A[l] = sum(cntR[0..l-1])。
- 初始化
-
计算 :
- 初始化
cntL[0..n+1]=0。 - 对每个节点 ,
cntL[L]++。 - 后缀和:
B[r] = sum(cntL[r+1..n])。
- 初始化
-
按 值分组:
- 建立
vector<int> bucket[N+1]。 - 对 ,将 加入
bucket[B[r]]。 - 对每个桶排序(其实按 顺序加入已经有序)。
- 建立
-
统计 :
-
初始化
g[0..N]=0。 -
对 :
(对所有 一起做,或者枚举 再找 ,这里选择枚举 和 ):
实际上我们可以对每个 ,遍历所有可能的 (即 ),但 必须是 的值,所以改为:
枚举 ,,对于每个 使得存在 满足 ,那么 , 加上 中 的 个数。 这里 取值最多 种,但 ,,所以 仍不行。优化:
反过来枚举 :
对每个 ,我们求满足 且 的对数。
可以用两个指针:
将 按 分组, 按 分组。
对 ,,在 和 中找到 的对数,这可以用双指针在总 内完成对所有 的计算。更简单:直接枚举 ,,,在 中二分找 的个数,累加到 。
这样复杂度 。
-
-
回答询问:
读入 ,若 或 输出 ,否则输出 。
复杂度分析
- 建树:
- 计算 :
- 分组:
- 统计 :
- 回答 个询问:
总复杂度 ,可以处理 。
关键点
- 将“时间复杂度”转化为“相交节点数”。
- 利用 分离变量。
- 通过桶分组 + 二分统计满足 的区间对数。
- 注意 , 的有效范围有限。
- 1
信息
- ID
- 5936
- 时间
- 5000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 3
- 已通过
- 1
- 上传者