大哥哥,我想学数据结构
CF2066E Tropical Season
肯定先考虑判定是否合法。观察到:
- 初始需要有两个权值一样的数,否则必然无解。
- 如果权值为 \(i\) 的数已经被确定,那么所有 \(<i\) 的数都将被确定。注意到肯定有多余的桶装水后显然。
- 如果确定的数之和为 \(s\),那么我们能确定 \(a_i\le s\) 的 \(i\) 或 \(a_j-a_i\le s\) 的 \((i,j)\) 对。那么如果无解,说明必然存在一个分界线使得前面都选中后面都选不中。
- 注意若只剩一个没法确定则还是有解,因为可以排除法。
- 根据前面的性质,我们最终得到判定条件:不考虑使用排除法的情况,若无解当且仅当不存在两个值相同的数或存在一个 \(p\) 使得 \(p\) 之前的所有数之和小于 \(p\) 之后 所有数的最小值 和 所有相邻数的差的最小值 的最小值。
- 使用排除法的情况比较简单,后面会讨论到。
考虑怎么维护这个 \(p\)。注意到只与值域相关,而且还有差值,不妨尝试倍增值域分块,将 \((2^{b-1},2^b]\) 分一块。注意到一个小性质:若一个块内存在一个元素被确定,则该块所有元素都会被确定。其实是比较显然的,因为如果一个数 \(x\) 被确定,说明被确定的数之和一定不小于 \(2x\),这高于这一块的值域上界。
利用这个性质,\(p\) 的枚举量就从 \(O(n)\) 变成了 \(O(\log V)\)。我们只需要维护块内最小值、块内最小距离、块间最小距离。前两个可以简单使用 set 维护,最后一个只需要枚举相邻的两个块然后用后面的最小值减前面的最大值即可。如果后面的块没有元素,也不需要枚举下下个块(虽然这样如果精细实现的话复杂度也没问题),因为若下一个元素在下下个块,说明元素之差已经大于下一个块的上界,它肯定会比这个块的最小值大。这样我们再维护一个最大值即可。
关于用排除法的情况,其实也好处理,若最大值所属块只有一个元素那么把这个元素扔掉即可。注意,此时这个元素的贡献仍然要保留。
时间复杂度 \(O((n+q)\log V)\)。
P5537 【XR-3】系统设计
显然不能直接做。发现树的形态不改变,观察到走到一个点的序列我们其实是能提前知道的,查询就相当于找所有点的序列中(只截取从 \(x\) 出发的部分)最长的与 \(a_{l,\cdots,r}\) 相等的序列长度,这显然可以二分。但这样不优美,我们可以预处理出从根出发的序列 \(A_i\),如果是从 \(x\) 开始走,设二分值为 \(mid\),则相当于查询满足 \(A_x+a_{l,\cdots,mid}=A_y\) 的 \(y\) 的存在性,用线段树维护 \(a\) 序列,二分过程改成线段树二分即可。复杂度 \(O(n\log n)\)。
QOJ7415 Fast Spanning Tree
减半警报器。发现一个点上可能有多个警报器,我们考虑给每条边拆成两个点,把警报器放在拆的点上,这样能好做一点。对于每个点,钦定它是其所在连通块的代表元,考虑维护一个 pq 存所有警报器,警报器存两个信息,其放在堆内的权值和其初始权值,放在堆内的权值=初始权值+警报器阈值(本质是打标记)。当警报器被激活,初始权值变更为激活时连通块的权值和。再维护一个大堆存所有小堆的堆内最小值减连通块权值和,每次取这玩意非正的即可。由于警报器被激活时所属这条边的另一个警报器也要更新,所以堆需要可删。连边直接启发式合并即可。时间复杂度 \(O(n\log n\log V)\),写平板电视堆被卡了。

浙公网安备 33010602011771号