2022 第一轮省队集训 Day6
T1
扫描线扫序列维。将每个询问差分成前缀询问。如果以时间为纵轴,序列为横轴,每个修改影响的就是一个 3-side 矩形,查询就是一个与 \(x\) 轴平行的线段,且左端点在 \(y\) 轴上。
所以,我们只需要对于每个时间,都维护答案的历史和。当在序列位置 \(i\),时间 \(t\) 插入(或者删除)一个值时,它只会改变 \(x=i,y\ge t\) 的 \(\log n\) 个非 \(1\) 位置的答案。用平衡树维护即可。
时间复杂度 \(O(n\log n\log A+q\log n)\)。
T2
感谢 kdw。
先考虑没有重复的数怎么做。
值域分块,那么块间的信息是可以 \(O(1)\) 合并的。考虑整块怎么做:因为其中有 \(O(\sqrt{n})\) 个值,所以可以暴力维护每个区间内的答案。对于每个块,我们设 \(f_i\) 为序列上的第 \(i\) 个位置前面,最靠后的一个值在这个块内的位置。所以可以 \(O(1)\) 算出序列上一段区间在这个整块内的答案。
对于散块,我们可以记录值域块内出现过的值以及它在序列上的位置,因为散块大小之和是 \(O(q\sqrt{n})\) 的,所以离散化以后直接扫就行了。
如果有重复的数,我们不均匀地分块,以保证相等的数在同一块内:设最小的 \(i\) 种数分的最后一个块大小为 \(S\),设当前要加入一个新数,它的出现次数是 \(c\),如果 \(S+c\le \sqrt{n}\),就把新的数分到最后一个块内;否则新开一个块。
这样,我们可以保证仍然只分了 \(O(\sqrt{n})\) 个块。再考虑询问:对于一个长度 \(>\sqrt{n}\) 的块,其中只有一种值,我们只需要确定序列上的某个区间内是否有这种值。因为这样的块的个数是 \(O(\sqrt{n})\) 的,对于每个块,只需要预处理每个位置后面第一个这种值即可。
对于一个长度不超过 \(O(\sqrt{n})\) 的块,如果是整块查询,本质不同的查询仍然只有 \(O(n)\) 种,暴力预处理即可。对于散块查询,将这 \(O(m)\) 个散块查询离线后莫队即可。
T3
分治信息。
UOJ 515 前进四
给定整数序列 \(\{a_n\}\),支持两种操作:
- 单点修改;
- 给定 \(x\),询问 \(i\ge x\) 的 \(a_i\) 中,有多少个满足 \(a_i<\min(a_{i+1},a_{i+2},\dots,a_{n})\)。
扫描线扫序列维,数据结构维护每个时间对应的答案。我们要支持的就是:
- 区间取 \(\min\);
- 求某个位置被取 \(\min\) 了多少次。
所以用 Segment Tree Beats 即可。
Comet OJ #14 D
给定一个长为 \(m\) 的操作序列,每次形如“将序列的 \([l_i,r_i]\) 位置赋值成 \(a_i\)”。
有 \(q\) 次询问,每次问初始将序列赋值成 \(0\),然后执行 \([l,r]\) 间的操作,得到的序列的所有数之和是多少。
扫描线扫右端点,只需要用 set 维护每个连续段以及它产生的时间。在 \(t\) 时间询问,就是问所有时间 \(\ge t\) 的连续段的值之和。树状数组维护即可。
P6109 [Ynoi2009] rprmq1
感谢 dwt 的教导。
这种先修改后询问的可以考虑扫描线。但 \(\max\) 不具有可减性,考虑分治,每次只需要计算跨过分治中线的询问的答案。
将每个询问拆成左、右两个。由于两边是对称的,只讨论每个分治中线右边的询问。这样只需要求 3-side 矩形的 \(\max\)。
我们一共会进行 \(O(\log n)\) 层分治,且分治中线的个数是 \(n\)。对于每一层,我们用扫描线向右扫,并用数据结构维护每个区间到上一个分治中线的历史最大值。
那么我们需要支持的是:
- 区间加;
- 求区间历史最大值;
- 将所有区间的历史最大值都赋值成当前这个区间的最大值。
考虑用线段树,前两个操作直接做。对于第三个操作,我们直接将所有位置都加上一个很大的数即可。
时间复杂度 \(O((n+m)\log^2 n+q\log n)\)。
P7899 [Ynoi2006] rprmq2
P7446/CF1491H [Ynoi2007] rfplca
维护出树的结构是很困难的,但求 LCA 并不需要求出具体的结构。
考虑分 \(O(\sqrt{n})\) 块。设 \(f_u\) 为点 \(u\) 恰好跳出当前块时跳到的位置。假如某个整块被减的 \(x\) 的总和 \(>\sqrt{n}\),那么这个块中的所有点跳一次都会跳出。此时如果再对这个块做整体的修改,那直接打一个 tag 即可。
否则,我们暴力重构这个块的 \(f\)。对于一个块,重构的复杂度是 \(O(\sqrt{n})\),一共有 \(O(\sqrt{n})\) 个块,每个块会被重构 \(O(\sqrt{n})\) 次。所以这部分的复杂度是 \(O(n\sqrt{n})\)。
对于零散块的修改,直接暴力重构即可。
对于一个询问 \((u,v)\),利用 \(f\) 和 \(a\) 暴力跳即可,有一点细节。
时间复杂度 \(O((n+m)\sqrt{n})\)。
CF700D Huffman Coding on Segment
CF1476G Minimum Difference
好萌的题。
先考虑如果没有修改怎么做:用莫队维护每种出现次数的个数,因为所有出现次数之和是区间长度,所以不同的出现次数只有 \(O(\sqrt{L})\) 种,\(L\) 是区间长度。
对于询问,我们枚举选择的最小的出现次数,然后双指针即可。
对于修改,直接套个带修莫队就行了。
牛大了的题
空间内有 \(n\) 个长方体,求它们的体积并。\(1\le n\le 10^5\),10s。
对某一维扫描线,那么要解决的问题就是:
- 矩形加、减,且保证每个位置的值始终 \(\ge 0\)。
- 询问全局的 \(>0\) 的位置个数。
然后直接就是 rprmq2 了。虽然我不会做。