Loading

省选二轮培训day 2

省队集训 day 2

考试题

T1

给定一个 \(n\) 个点 \(n\) 条边的图,每个点有点权,有一条边 \((a,b)\) 表示 \(a\) 可以分配任意多他的边权(整数)给 \(b\) ,并且我们可以分配 \(m\) 个边权给任意点,求最小点权的点最大是多少。

  • 解析:
  • 当看到这个最小值最大的问题,我们考虑二分。发现这个图实际上是一个环套树森林,我们对于每一课环套树,我们考虑上面的那个问题,取最值即可。我们考虑现在二分到的值为 \(mid\) ,然后把基环树环上点缩成一个结点,对于所有节点,令他们的 \(f\) 值减去 \(mid\) ,然后考虑如果 \(x\)\(f\) 值为负,就令 \(f_{fa_x}=f_{fa_x}+f_x\) ,否则不向上转移贡献。
  • 当所有信息集中在环上时,对环进行一次类似的操作,看一看有没有答案是负数的,如果有,说明这个数太大,否则说明这个数过小。
  • 常数优化时,建议先预处理拓扑序,然后在拓扑序上做 dp。

T2

给定一个序列,要求所有序列在这三个序列的极差乘积之和。

  • 解析:
  • 这个题给了 \(60\) 分的部分分,可以通过 \(O(n^2)\) 扫,推式子维护前缀和来解决。我们下面关注正解。
  • 我们考虑扫描线+单调栈。固定一个右端点,左端点不断向左扩展,最小值稳降不升,这是一个类似于栈的结构。我们在向右移动右端点时,考虑如果它比一些左端点小,就不断弹出左端点,同时维护序列极差和,均摊弹出 \(O(n)\) 次。对所有序列都做一遍,总复杂度 \(O(n\log n)\)

T3

给定一个长度为 \(n\) 的序列 \(a\) ,每一个元素 \(a_i\) ,代表着一个线性运算 \(x^*=|x-a_i|\),有 \(m\) 个询问,对应每一个询问有一个 \(l,r,v\) 。表示数 \(v\)\(l\) 开始到 \(r\) ,做线性运算。

  • 解析:
  • 首先写在前面,我觉得题解都比 lxl 讲得好
  • 我们考虑维护一个可持久化平衡树,一开始令其为恒等映射,每次加入一个映射后,相当于把一段区间复制过来,您一段区间反转复制过来,两端区间依据正负来分。
  • 对于询问我们需要对序列分治,即需要一个线段树,那么最后的数据结构实际上是线段树套可持久化平衡树。
  • 我们在这基础上进行常数优化,线段树最底层可以分块,最上层去掉 \(O(\log\log n)\) 个结点,因为这些节点对答案都没有贡献。线段树可以直接把右儿子插入到左儿子以此来达到父亲节点的可持久化平衡树。
  • 总复杂度 \(O((n+m)\log n\log v)\)

杂题选讲

T1 CF464E The Classic Problem 3000

给定一个 \(n\) 个点 \(m\) 条边的图,边权为 \(2^{x_i}\) ,其中 \(x_i\) 是我们给定的。求 \(s\)\(t\) 的最短路。

  • 解析:
  • 考虑最短路,因为边权为正,所以我们直接用 dij 即可,但是因为边权太大,所以我们需要高效的维护高精度。考虑到边权都是 \(2^{x_i}\) 的形式,我们把其压成二进制,这个二进制数需要进行加法和比较大小。
  • 我们发现 dij 中的这个语句 d[x]=d[y]+dis(x,y) 等价于将 d[y] 复制过来。然后再进行修改,所以我们考虑用可持久化数据结构。
  • 我们可以用可持久化线段树来维护。边权的特殊性导致我们只能发生一次进位,我们只需要在线段树上二分+区间修改打标记就可以。
  • 同时,我们可以用区间 LCP 的方法比较大小。
  • 复杂度:\(O((m+n\log n)\log x)\)

CF1446D2 Frequency Problem 3000

给一个序列,求最长的子段使得其中有至少两个出现次数最多的元素。输出最长子段长度。

  • 解析:
  • 考虑一下如果区间里有两个众数,那么这个题就结束了。
  • 否则,那么题目中的这两个数中的一个一定是这个序列的众数,而我们通过删除这个序列的一个前缀,一个后缀,让其出现两个众数。
  • 设这个众数为 \(x\) ,初始将每个 \(x\) 出现的位置标记为无意义的位置,我们枚举 \(y\) 出现的每一个位置,然后找距离这些位置最近无意义的 \(x\) 的使其变为有意义。
  • 所以只有 \(O(b)\) 个可能的答案端点,我们用序列线性并查集来做这个事情,我们需要查询前驱与删点,把 \(x\) 的位置设为 \(1\) ,把 \(y\) 的位置改为 \(-1\) ,这个对有意义的位置上前缀和,这个题就做完了。

CF997E Good Subsegments 3000

  • 这个题我不会
  • 考虑将每个区间表示为二维平面上的点(x,y)
    首先先初始化(x,y)的权值为y-x:对x=1…n进行矩形减,对y=1…n进行矩形加
    然后对序列进行最值分治,每次分治相当于一个矩形内的点对应的序列上的区间的max都是分治中心,进行矩形加,min同理进行矩形减。
  • 问题即转换为给定一个平面,进行O(n)次矩形加减,问一个矩形内有多少个0
    先将矩形差分,为3-side矩形,即一维是[l,r]一维是[1,x]
    然后使用扫描线+线段树沿着[1,x]的维扫这个平面
    由于保证矩形中元素非负,线段树维护区间min和min的个数,即可计算0的个数
    问题是3-side矩形在扫描线后,需要查询一个区间在一个前缀时间中的0的个数
  • 这个其实可以简单维护
    我们只需要对每个区间记录下多少个0,这个表示为量A
    然后有一个量B表示累计的历史贡献
    然后每次扫描线走一步的时候打一个区间B+=A的标记

CF765F Souvenirs 3100

区间查两个数的差的最小绝对值。

  • 解析:
  • 我们考虑哪些二元组 \((x,y)\) 对答案有贡献。考虑到若 \(a_i<a_j<a_k\),那么 \((i,k)\) 就被 \(i,j\) 给覆盖掉了。
  • 我们对以上的三个变量进行分类讨论,不妨设 \(a_i<a_j,a_k<a_j\) ,讨论如下:
    1. 如果 \(a_i>a_k\)\(|a_j-a_k|>|a_i-a_k|\),有 \(|a_i-a_k|<\dfrac{1}{2}|a_i-a_j|\),值域减半
    2. 如果 \(a_i<a_k\) 可以类比 \(1\) 来处理。
  • 总共有贡献的二元组有 \(O(n\log v)\) 个,我们用扫描线+线段树进行处理。

CF176E Archaeology 3100

这个题彻底没听懂,就不整理了。

据说 top tree 可以做,回头学一下。

CF700D Huffman Coding on Segment 3100

  • 解析:
  • 哈夫曼编码就是把每个出现过的元素提出来,按照出现次数加权,做合并果子
    哈夫曼树在排序后可以做到线性
    维护两个队列,第一个是初始的所有排好序的元素,第二个保存合成的所有元素,初始为空
    每次从每个队列中选前2大的元素,找最小的两个合成,合成后放入第二个队列末端
  • 有一个性质是不同的出现次数是O(sqrtn)的,考虑1+2+…+n=n(n+1)/2
    考虑使用莫队维护出区间每个数的出现次数,从小到大排序
    这个有多种维护方法,我之前写过的方法是记录下莫队转移时所有变化,然后到一个查询区间时一起处理掉,用莫队上一个处理的询问维护的区间不同的出现次数,以及记录的转移,得到这个区间的所有出现次数
    为了得到有序的出现次数,可以使用基数排序,也可以莫队转移时直接维护
    时间复杂度O(nsqrtm+msqrtn)
  • 这里考虑可以批处理同一个出现次数出现很多次的情况
    如果当前最小是相同的x个a,则可以合并出x/2个2a
    我们边维护两个队列边缩点
    复杂度分析:
    每O(1)次合并,下一次可能合并出的元素大小至少变大1
    经过O(sqrtn)次合并,只可能合并出>sqrtn的元素了
    而这两个队列如果均>sqrtn,则有O(sqrtn)个元素
    每次合并减少一个元素,此时合并O(sqrtn)次
    总时间复杂度O(nsqrtm+msqrtn)

CF1476G Minimum Difference 3100

  • 解析:

  • 有一个性质是不同的出现次数是O(sqrtn)的,考虑1+2+…+n=n(n+1)/2
    考虑使用莫队维护出区间每个数的出现次数,从小到大排序
    这个有多种维护方法,我之前写过的方法是记录下莫队转移时所有变化,然后到一个查询区间时一起处理掉,用莫队上一个处理的询问维护的区间不同的出现次数,以及记录的转移,得到这个区间的所有出现次数
    为了得到有序的出现次数,可以使用基数排序,也可以莫队转移时直接维护
    时间复杂度O(nsqrtm+msqrtn)

  • 这道题中直接使用带修改莫队维护区间本质不同出现次数
    查询时用双指针在不同出现次数的结构上扫即可维护出答案

    总时间复杂度O(nm^2/3+msqrtn)

CF1344E Train Tracks 3100

这个题我没有听懂。

  • 解析:
  • 考虑对每个点,维护出到其的所有火车的时刻
    对原树进行启发式合并的过程
    对重儿子维护一个全局标记,将每个轻儿子的数据结构加上一个边权,合并进来
    如果在最终合并出的数据结构中,有x为y的前驱,且x和y来自于不同的儿子,则在[x+1,y]时刻中必须进行一次切换,不然就会爆炸
    启发式合并过程的复杂度:
    使用平衡树是O(n+mlognlogm),vEB树是O(n+mlognloglogm)
    (实际上我觉得是O(n+mlogmin(n,m)loglogm))
  • 可以发现上述的约束条件是充分必要条件
    启发式合并导致总共有O(mlogmin(n,m))个时间段区间
    问题转换为给定一个序列,有一些区间,将序列的每个位置分配给包含其的某个区间,使得每个区间均被分配一个位置
    扫描线从左到右扫序列,使用数据结构维护当前没有处理的区间里最靠左的一个右端点,问题即转换为插入删除查询前驱
    使用平衡树可以做到1log,有O(mlogmin(n,m))次修改
    使用vEB树可以做到:
    总时间复杂度O((n+mlogmin(n,m))loglogm)
  • 如果这里的时间t=n的话有个更好复杂度的做法
    可以发现,若最后的时间段数>2n,则一定出现爆炸
    因为每秒只能切换一次,故总共最多切换n次
    如果只是验证可行性的话,则时间段数>2n时直接输出NO
    这样可以限制时间段数O(n)
    然后我觉得可以用splay启发式合并证O(n+mlogm)的启发式合并的复杂度
    这样时间复杂度可以优化为O(nloglogm+mlogm)

小结

听不懂的主要原因是有一些前置知识并不会,应当改变重心,从刷题转移到学习算法与数据结构上来。

posted @ 2021-05-31 19:41  hyl天梦  阅读(89)  评论(0编辑  收藏  举报