P9970 [THUPC 2024 初赛] 套娃
题面
定义一个集合的 \(\operatorname{mex}\) 是最小的不在 \(S\) 中的非负整数。给定一个序列 \(a_1,\dots,a_n\),对于每个 \(1\leq k\leq n\),我们按照如下方式定义 \(b_k\):
- 对于 \(a\) 的所有长为 \(k\) 的子区间,求出这个子区间构成的数集的 \(\operatorname{mex}\)。
- 对于求出的所有 \(\operatorname{mex}\),求出这个数集自己的 \(\operatorname{mex}\),记为 \(b_k\)。
请你求出序列 \(b\)。
数据范围:\(1\leq n\leq 10^5,a_i\leq n\)。
题解
感觉挺难的啊,为毛过了一车人...
总体的思路是找到形如 \([l_1,r_1]\) 和 \([l_2,r_2]\) 这样的区间,使 \(l\in[l_1,r_1],r\in[l_2,r_2],mex(a_l\sim a_r)=t\) ,那么我们就可以对 \(k\) 在 \(l_2-r_1+1\sim r_2-l_1+1\) 的这些 \(b_k\) 都加上 \(t\) 元素,将这些修改操作扫描线处理一下,然后就可以用线段树上二分的方式找最小的没有出现的元素。
现在考虑去求这样的区间。
首先是一个结论:记最小 \(mex\) 区间表示:对于一个区间 \([l,r]\),不存在一个子区间 \([l_1,r_1]\),使 \(\text{mex}(a_l\sim a_r)=\text{mex}(a_{l_1} \sim a_{r_1})\) ,那么一个序列的所有最小 \(mex\) 区间的数量是 \(O(n)\) 的。
证明:对于一个满足条件的最小的 \(mex\) 区间 \([l,r]\), 显然满足 \(a_l\neq a_r\),否则删任意一个不影响答案。不妨假设 \(a_l>a_r\),那么有 \(mex(a_l\sim a_r)\ge a_l> a_r\)。
此时如果还存在一个 \(r_1\) 使得 \(r_1>r\and a_l>a_{r_1}\) ,那么 \(a_{r_1}\) 一定在 \(a_l\sim a_r\) 中出现过了(不然 \(mex(a_l\sim a_r)\) 不会大于等于 \(a_l\)),那么对于一个 \(a_i\) 来说,那些比他 \(a_j\) 大,并且和 \(i\) 组成最小 \(mex\)区间的 \(j\) 只会出现最多 \(2\) 次,那么整个序列最多就是 \(2n\) 个最小 \(mex\) 序列。
现在我们考虑维护所有的最小 \(mex\) 区间 \((l,r,k),k=mex(a_l\sim a_r)\),考虑往其两边扩展,那么就是找到 \(l\) 左边和 \(r\) 右边最近的 \(t\) 使 \(a_t=k\) ,求出其 \(mex\),那么就可以找到所有可能的最小 \(mex\) 区间。
注意并不是一定,如 \(2,1,0,1,0\),那么 \((4,5,2)\) 往左扩展会到 \((1,5,3)\) ,很明显不是最小 \(mex\) 区间。
对于一组最小 \(mex\) 区间,求出其最大 \(mex\) 区间是比较显然的,左右端点就是 \(l\) 左边和 \(r\) 右边最近的 \(k\) ,在计算扩展区间的时候就已经处理出来了。
那么我们整个算法流程就是:
- 预处理出极小的 \((*,*,0)\) 和 \((*,*,1)\) 的区间。
- 对于每一个 \((l,r,x)\) 区间,分别求出其距离左端点最近的 \(x\) 出现位置 \(l_1\),和距离右端点最近的 \(x−1\) 出现位置 \(r_1\),形成两个新的区间,算一下 \((l_1,r),(l,r_1)\) 的 \(mex\),然后丢到对应的存储 \((*,*,x')\) 区间的
vector
里,并且将 \([l_1+1,l],[r,r_1-1],x\) 记录下来后续处理。 - 对于每一个 \(x\) ,先将删去被包含的区间,在对每一个 \((*,*,x)\) 进行扩展。
注意这里要有一个在线求 \([l,r]\) 的算法,就是 P4137 。考虑建立一个主席树,每一个节点 \([l,r]\) 存的是 \((a_l\sim a_r)\) 中最晚出现的下表,这样在查询 \(l,r\) 的时候我们就在 \(r\) 那一棵树上找出现时间 \(<l\) 的最小的节点是什么。
启发
- 关于 \(mex\) 的一个结论:一个序列的所有最小 \(mex\) 区间的数量是 \(O(n)\) 的。
- 关于求区间 \(mex\) 的算法:主席树+线段树二分。