题好难,不嘻嘻(2)。
只保留了我认为比较有意义的题(2)。
我怎么感觉所有题最后都会保留。
CF1707E Replace
题意
给定一个长度为
定义
给定
题解
为啥这 3500 的题一个白天就过了快 40 个人。
首先可以知道一个结论是
这个比较显然,因为容易证明得到的两个区间左右端点一样,并且中间肯定是连续的。
然后还有
这个容易归纳证明,首先
然后假设
那么一定
所以显然
那么这个时候就会发现
一样,左右端点归纳一下,然后中间还是连续的,所以是相当的。
那么现在考虑我们怎么样回答答案。
首先如果
否则如果不存在
否则一定会有
考虑能不能维护出来
假设我们知道
那么我们直接倍增再套一个 st 表就对了。时间复杂度
提交记录。
CF1852F Panda Meetups
题意
现在有一个数轴和
时刻在 这个位置插入 个红点。 每一个红点在每一个时刻可以选择往左走一步、原地不动或向右走一步。
时刻在 这个位置插入 个蓝点,蓝点下一个时刻就会消失。 但是如果在
时刻 上面有 个红点,那他们会造成 对匹配,匹配的点会消失。
对于每一个操作的前缀,求出最大的匹配个数。
保证操作按照
题解
先考虑静态的区间怎么做,考虑把蓝点和红点画在一个平面上。
一个红点可以匹配它上方的蓝点,所以这可以看作一个匹配问题。
直接跑网络流显然不太可能,所以我们考虑求出这张图的最大独立集。
也就是说,我们要尽可能选出更多的蓝点和红点,使得没有任意一堆点可以匹配。
那么就能发现,一定存在一条分割线,使得线上面的所有红点都被选中,线下面的所有蓝点都被选中。
并且这条边在
由于每一次加点
那么直接令
第一种操作是把 dp 往后转移一个位置,那么
第二种操作是遇到一个点,直接给一段前缀或者一段后缀整体
那么我们考虑维护
考虑如果扫到位置往后挪了一个,那么差分为正的位置会往左走,为负的位置会往右走。
由于一负一正相撞之后会抵消一部分,所以还需要维护最近的两个一负一正的位置。
时间复杂度
提交记录。
CF1523H Hopping Around the Array
题意
现在有
给定
题解
考虑
可以发现,(除了最后一步以外)我们每一次跳到的点,一定是能跳到的,满足
那么就可以直接
询问的时候就直接算出跳多少步能跳到一个
那么现在考虑
设
询问的时候处理方式相同,时间复杂度
提交记录。
CF1824E LuoTianyi and Cartridge
题意
给定一棵树
现在你需要建一棵新树
选择一条
要求
然后将这条边加入
令最后建出的
题解
先来考虑,假设已经给定了选择的点集与边集,怎么判断能否连出一棵合法的树。
考虑对于任何一个不在边集内的边,我们把他的两个顶点缩起来。
这样可以得到一棵新的树,满足树上的所有边都在边集以内。
(其中黄色的为选中的边集或点集)。
可以发现,如果存在某一个叶子,满足其中没有黄色点,那么一定是连不出来的。
否则一定可以连出来,构造的方式是,每一次考虑一条还没有被用过的边。
此时所有点一定被分为
那么一定能从左边选出一个连通块,然后从右边选出一个不同的连通块,然后把这两个连通块连起来就好了。
这样我们就会判断一个方案是否合法了。
那么考虑原题怎么做呢,首先答案中出现了
枚举了之后,原树上有一些边和点是能选的,那我们还是一样把不能选的边都缩起来。
那么现在问题在于如何取点和边。
首先,对于某侧没有叶子的可选边,他实际上和不可选没什么区别,我们把他删掉(这样点集的叶子更好定义一些)。
然后,对于所有叶子,其内部必然要选至少一个点(否则与他相连的边就选不成了)。
所以每一个叶子中,可选的点里面
那么这样,我们的边集无论选成什么样子,就都是合法的了,所以在剩下的点和边里面都直接挑权值大的挨个选就好了。
那么这样就能做到
我们从小到大枚举
删掉一条边的时候,相当于合并其左右的两个点,我们使用启发式合并给这两个点并一下(需要注意两个点会变成叶子之类的问题)。
删掉一个点就是直接删了(大雾),同时也要注意此时可能连带删掉一个边,然后让别的点变成叶子。
可能还需要两个线段树之类的东西维护点权和边权的前
时间复杂度
提交记录。
CF2018E Complex Segments
题意
给定
现在要选出若干个区间,并将它们分为若干组,满足:
- 两个区间有交当且仅当他们被分在了同一组;
- 每一组的区间个数相等。
求出选出的线段个数最大值。
题解
这题看上去就不太能直接做,所以考虑暴力一点的方法,先枚举
设答案为
具体来说,考虑第一组怎么选,容易发现在合法的前提下,右端点的最大值肯定是越小越好。
那么我们将所有线段按照右端点进行排序,每一次假如一条线段,如果加入之后存在一个位置被覆盖了
第一组结束之后,假设第一组右端点最大值是
这样我们就能求出如果一组有
其实这个部分还能优化,假设有两个位置
那么可以发现,
也就是说,我们其实只需要维护覆盖次数为后缀
那么直接使用一个链表,把所有最大值的位置串起来,并且维护他比前面一个后缀最大值小了多少。
假设现在新来了一条线段
那么问题在于如何找到
那就再用并查集维护每一个点后面的第一个后缀最大值位置,当某个点不是后缀最大值了的时候,把他并到他后面那个点上就好了。
忽略并查集复杂度的话,这样我们就可以在
考虑到
那么我们使用分治来进行优化,考虑假设我们现在分治到了一个区间
如果此时
否则我们计算出
因为
时间复杂度
感觉是最好写的一个题
提交记录。
CF1876G Clubstep
题意
给定一个长度为
现在可以进行若干种操作,第
题解
考虑单组询问怎么做,容易发现直接从后往前贪就对了。
具体来说,找到最后一个满足
那么可以发现,设
大概就是扫到
暴力的方法是对于平衡树的一段
但是不难发现,在扫过几个位置之后,不同
那么我们合并
那么定义势能函数
那么考虑,如果
如果
也就是说,我们没多扫过一个位置,势能会减少大概
所以合并相同的
提交记录。
QOJ9918 Master of Both VI
题意
现在有
给定
,给 这条路径上的所有怪物施加 的伤害。已知点
上有一只血量为 的怪物,已知他现在血量 ,但你不知道他是什么时候出现在这个点上的。你需要求出,这只怪物最多接受了多少次攻击。
特殊的,在怪物遭遇攻击的时候,可以使用技能,使自己收到的伤害减半(实数)。
但是,怪物不能在相邻两次攻击中,都使用技能。
题解
首先给所有伤害和血量
先来考虑,一个暴力一点的做法。
我们首先暴力维护出每一个点按照时间顺序依次受到了哪些攻击。
然后对于一个询问,假设这个点目前一共受到了
那么做一个 dp,其中
这样复杂度是
假设第
也就是说这个 dp 的过程可以使用线段树来优化。
我们以时间为轴,建一棵线段树出来,那么一组询问相当于是确定了一个右端点,要求我们找出一个最小的左端点。
这样
假设所有攻击都满足
那么考虑直接在
时间复杂度
提交记录。
CF1515H Phoenix and Bits
题意
给定
- 将
的所有 变为 。 - 查询
有多少不同的 。
注意上面的操作是对值域而不是下标。
题解
首先考虑还是得用 trie,区间操作的话就先 split 出来然后再 merge。
然后查询查的是有多少不同的数字,所以如果有需要合并的地方,一定要立刻合并。
那么对于每一个点维护,其子树内,哪些层,出现了点,同时有两个儿子。
然后直接 dfs 下去,需要合并的就直接合并,剩下的打一个 tag 就解决了。
tag 可以使用位运算
时间复杂度
提交记录。
QOJ9559 The Tower
题意
现在有一个弹幕网站,初始的时候所有行都是空的,按照时间发生了
- 新来了一个用户发了
条弹幕,他会占用此时最上面的 个空行; - 一个用户跑路了,他占用的行会变成空行;
- 查询某个行现在被哪个用户占用。
题解
先不考虑询问问什么,考虑怎么维护前两个操作。
可以发现,这个比较容易用线段树分裂求出来。
问题在于,询问的时候我们需要知道某个节点在哪一棵树里面,这不是很好做。
一个想法是,我们维护一下,线段树上面每一个叶子,分别在哪颗树里面。
然后 set 维护一下,这样就是两个
那我们考虑,再开一个线段树,这棵线段树记录的是,每一个区间,在那边的线段树森林里面,节点编号是多少。
这样对于询问,我们只需要在新开的这棵线段树上面从上往下找就好了,然后找到对应的节点之后,再从下往上跳。
提交记录。
CF1942H Farmer John's Favorite Intern
题意
现在有一棵
定义一次在
定义一次在
给定
你需要对于操作的每一个前缀,求出,是否能够重排操作,使得过程中所有
题解
因为操作可以重排,所以过程中
那么先来考虑,对于整体怎么判断是否有解。
考虑一个在
也可以匹配一个在
那么考虑从下往上贪心,一个点的生长操作,应当优先匹配自己子树内的东西。
然后优先匹配父亲的
那么直接维护
这样我们就会算单个前缀答案。
我们写一个暴力发现没有问题
懒得写了之后再说