DS1
DS1
题单:DS1
1.成都七中
做法一:点分治
题目要求的东西与 \(x\) 联通的编号在一段区间的颜色数,暴力做是从一个点往外搜,我们想找尽量少的点向外搜索。
我们考虑一件事情,如果我们确定了连通块中的某一个点,那么其他点实际上是以这个点为中心的路径上满足要求的点的并。我们发现需要连通块的一个点和树上的路径信息,可以考虑点分治。
考虑当前分治中心 \(u\),给每个点附上一个 \(L_x\) 和 \(R_x\),表示取到这个点需要满足的最小询问区间。再当前分治中的与到 \(u\) 路径上满足询问要求的点找出来,要求即是 \(ql_i \leq L_x \leq R_x \leq qr_i\)。那么询问答案即是一个简单的二维数点,复杂度显然 \(O(n \log^2n)\)。
启示:对于连通块问题中,考虑是否能把在一个连通块中的点统一放在尽量少的位置,方便统一查找。
做法二:两棵重构树子树求交的颜色数
鸽....
2.火灾
题意:给定序列 \(a\),\(k,l,r\),求 \(\sum_{i=l}^{r} \max\limits_{j=i-k+1}^{i} a_j\)。
做法一:单调栈建树
首先考虑进行 \(k\) 次操作后序列会有什么变化,发现这个操作肯定与左边第一个值比他大的位置有关,设 \(lt_i\) 表示 \(i\) 左边第一个大于它的数的位置。
那么发现把这个东西建出一棵树来后,每次覆盖都相当于化 \(i-lt_i\) 的时间往根链上跳,最后找到最后一个满足时间限制的祖先这个点的贡献就是这个祖先的值,这样的化就可以倍增做到 \(O(nq \log n)\)。
但这样倍增的化肯定是不好维护的,这个是从下往上找祖先给这个点的贡献,这样不优。我们考虑让祖先把贡献下传,对于这棵树发现一个很好的性质。
- 祖先的值都大于子孙。
- 一个点的子孙是一段区间。
- 贡献的下传中子辈给孙辈的下传早于父辈给孙辈的下穿,那么下传时只需下传 \(a_{fa_x}-a_x\) 的值即可。
由于祖先的值都大于子孙,我们完全可以把覆盖改成加。
又因为子孙是一段区间,且每次只用下穿一个 \(delta\) 我们可以用一个四元组 \([l,r,t,v]\) 刻画这件事情,表示从 时间 \(t\) 开始,依次给 \(l \sim r\) 的值加上 \(v\)。于是我们只需要暴力判断所有事件就可以做到 \(O(nq)\),而且这个做法看起来非常有前途!!!!
我们发现这里有很多区间操作,容易发现都有可差分性,考虑把他们全部变成前后缀。那么我们每次实际上就是这样的操作,我们需要统计 \([l,t,v]\) 给 \([r,k]\) 的贡献,暴力做时统计贡献是 \(v_i \times \max(0,\min(k-r_i+1,r-l_i+1))\),把 \(\max\) 拆掉就是当 \(k \geq r_i 且 r \geq l_i\) 时 \(\min \times v_i\),发现就算要钦定大小,典型三维数点,但这个题目比较独特,我们拆贡献的时候发现满足某些条件时会天然满足某些条件,之后可以二维数点。
做法二:变为 V 个 01 序列
在下一个严格强化版本中会提到。
3.pyramid
对于这道题,发现这个操作交替进行在值多的情况下实际上是相当复杂的。由于这里的操作只有 \(ckmax\) 和 \(ckmin\) 考虑把序列转成 \(V\) 个 01 序列,即 \(a_i = \sum_{v=1}^{\infty}[a_i \geq v]\),由于判断一个位置 \(x \geq v\),只与和 \(v\) 的相对大小有关。所以可以当作 \(V\) 个 01 序列,然后我们再分析操作。
- 发现前 \(cnt\) 次 \(ckmin\),实际上是把极长 \(1\) 段的右端点往左移动 \(cnt\) 。
- 后 \(cnt\) 次 \(ckmax\),实际上是把极长 \(1\) 段的左端点往左移动 \(cnt\)。
于是发现一整次操作实际是把 \(len \gt cnt\) 的区间往左平移 \(cnt\) 个单位长度。
\(len \leq cnt\) 的区间删除。注意到所有的极长 \(1\) 区间是相互独立的,他们只会自己平移或者消失。我们可以分开考虑这些区间对于答案的贡献。
但是如果我们每次都把每个 01 序列找出来那么有 \(O(nv)\) 个区间直接爆炸。我们发现每次变化最多影响 \(cnt_v\) 个区间,而 \(\sum cnt_v =n\),于是我们发现本质不同的极长1段只有 \(O(n)\) 个,那么我们找出这些区间。
然后我们考虑这些区间对于一个答案的贡献,发现对于一个前 \(x\) 次操作,我们可以提前算出前 \(x\) 次操作需要的最小区间长度,左右端点分别的偏移量,之后就是算两个区间的交乘贡献,注意到可差分性,拆成前缀和前缀的交乘贡献,后面是朴素二维数点,复杂度 \(O(n \log n)\)。
好像还有一个用二维平面刻画 01 序列的方法,本质应该差不多,先鸽了。
4.TEST_68
做法一:分治 + tire \(O(n \log n \log v)\)
考虑维护子树补信息,先建出 \(dfn\) 序,我们发现可以类似缺一分治往下递归,不同的是这个是区间,但由于我们的区间是子树,我们知道子树是没有相交关系的。
于是我们可以把一个区间往下递归,放在区间经过中心点的地方做,然后每次扫描左指针,然后右端点同时往左缩就可以了。
做法二:找性质 \(O(n \log v)\)
我们考虑先找出两个节点,他们是全局最大异或点对。他们支配除了到两点根链上的节点,两条链可以暴力从上往下扫,每次加点就可以了。
这道题感觉挺聪明,应该是个 trick 吧,叫补信息全局支配点。
5.地牢游戏
做法:倍增分块
看到题之后第一想法是只要跳到 \(10^7\) 就赢了,那么我们如果一次加的很多是非常优的,但是我们考虑输的时候我们无法保证我们的战斗力,于是我们考虑每次尽量只做大的赢的。我们考虑根号分治,直接先跳 \(\sqrt V\) 步,然后之后我们发现 \(s_i \leq B\) 就直接赢了,否则输的我们可以钦定他输了,然后预处理出输需要的条件。这样可以做到 \(O(q \sqrt V \log V)\)。发现无法通过。
考虑倍增分块,我们发现上面我们是分成两个阶段,我们完全可以多分几个阶段达到平衡时间的目的,注意太多块空间会爆,后面平衡一下就可以了。
6.梦想歌
做法一:暴力维护,\(O(n \log n \log V )\)
https://www.luogu.com.cn/article/hdrchkoo
做法二:建kruskal重构树,找重心
这个我暂时不会。
7.旅行
题目就是给你一棵树,和一个可重的编号序列,求编号序列一段区间的虚树大小。
做法一:回滚莫队
首先我们有经典结论,对于一个点集 \(S\),虚树大小为按 \(dfn\) 序从小往大排序后,相邻两个点的距离加上首尾两个点的距离除以 \(2\) 加 \(1\) 即为虚树大小。证明考虑构建虚树的过程即可。
那我们直接用莫队做就是 \(O(n \sqrt q \log n)\)。考虑怎么优化,我们发现我们每次都是在加删点,找前驱后继。我们发现如果我们只删不加的化我们直接用一个链表维护即可。
我们考虑回滚莫队,普通的回滚莫队是做不删除的,不加的化也是类似的。我们考虑对于这个块中,先加入 \([L_{bl_x},n]\) 中的所有点。
之后如果是右端点的会那你直接向左平移的时候一个一个删除就可以了,左端点的你发现你向右移动之后,你还是要把这些点加回来,这样就又错了,我们发现我们可以倒着一个一个加回来这样就变成撤销删除了,这是可以做的复杂度就正确了,复杂度同回滚莫队 \(O(n \sqrt q)\)。
做法二:树剖+数据结构
考虑区间内的每一个点对到根链上的所有点进行染色,那么我们发现虚树大小实际上就是被染色的点的个数 $ - dep[lca]+1 $,后面一段直接减掉就行了。
前面的我们考虑给每一个点到根链的颜色记作他的编号,那么我们考虑对 \(r\) 扫描线,发现你每次把到根链上的点的颜色都染成自己肯定不劣,那我们只需要实时维护每个颜色树量就可以了,我们直接在 \(dfn\) 序上建一个 \(ODT\) 就可以直接做了,复杂度显然是均摊的,\(O(n \log^2 n )\)。
实际上不用维护 \(ODT\),注意到操作是对重链的一段前缀覆盖,于是你直接对没一条重链从浅到深维护一段颜色段即可,常数会小一些。
8.学习轨迹
先考虑暴力怎么做,发现你只要枚举第一个序列左端点,之后扫描右端点然后加点就可以了,这个做法要维护所有极大区间,非常困难。如果第二个序列存在一个必经点的话,那只需要对于每一个 \(l\) 维护一个必经点所在区间的 \(l,r\) 就可以了是容易的。
存在一个性质是,我们一定会选择其中一个序列的带权中点,证明考虑如果没有选择的话不如把一个序列选完来的优秀,后面维护随便做。
9.无人机比赛
首先考虑暴力怎么做,只需要开个 \(pq\) 记录一下每个无人机到什么地方了,还有多少个无人机,直接每次拉出队首,然后再用队内元素算贡献就可以了。
我们发现如果继续再维护 \(pq\) 的话肯定没前途。我们直接算每一步的贡献就可以了。我们发现一步的贡献只和这一步的时候有多少个无人机和对于这个无人机前面的步骤中的排名最后的一步有关,那我们只要取个前缀 \(\max\) 然后再记录后面有多少个无人机就可以了。
进一步,我们发现我们只需要每次加入一个新的无人机的时候,算一下当前无人机最后一步对之前无人机的贡献,和之前无人机最后一步对当前无人机步骤的贡献就可以了,可以 \(O(nm \log n)\)。
进一步,有 \(\sum s_i = 10^5\),那本质不同排名只有根号个,我们把这个缩起来就可以了,然后注意到里面两个操作一个是加 \(n \sqrt n\) 次,查 \(1\) 次,另一个是 加 \(n\) 次,查 \(n \sqrt n\) 次,用两个根号平衡即可,复杂度 \(O(n \sqrt n)\)。
10.水果游戏
首先这个问题静态有两个做法:
做法一: \(O(n \log n)\)。
就是你从小往大考虑值域,然后对于一个同色连续段,若是 \(len \bmod 2==0\),那么显然直接长度减半,值域加一,否则两边一定不会再有关联了。
我们直接加入
\(\underbrace{(x+1)+\cdots+(x+1)}_{\text{len/2个}}
\,x\,
\underbrace{(x+1)+\cdots+(x+1)}_{\text{len/2个}}\)
由于两边之后就无关了,所以这样做是正确的。
做法二:O(n)
考虑我们现在已经维护好了前缀的答案,考虑新加入一个元素造成贡献。设当前序列为 \(a\),长度为 \(m\),我们维护的是每个颜色的连续段。发现如果新加入的值 满足 $a_{m-1} >a_m $且 \(a_m < w\) 的话,我们需要决策 \(a_m\) 这个点,否则直接加入新的点。
我们考虑判断中间点 \(m\) 的个数是否可以整除 \(2^{\min(a_{m-1},w)-a_m}\),若可以
的话,那就把中间的点缩一下之后再合并就可以了,否则和上面做法一样,两边都加入一个新的值段,再在中间加上一个间隔符即可。
带修查区间
然后我们再来考虑这道题目,显然对于上面两种做法第二种显然是更加容易合并的,那既然这样的话我们可以在线段树上维护一段区间剩下的值,和这个区间合并出来的最大数是多少。
我们对于区间合并做上面的做法,然后对于一个段,若两段出现最大值那显然他们只能内部自己合并,算出答案并把其删去,显然每个点维护的颜色段只会有 \(O(V+\log n)\) 个,因为再多就会出现上面讨论的 “谷”,我们就会把谷继续操作成峰,于是直接放在线段树上合并复杂度就是 \(O(q \log n (\log n +V))\) 的,可以通过。

浙公网安备 33010602011771号