2025.1.15 CQFLS讲课

以一道题目引入:给定一个长度为n的数列A,要求查询其中的第k小数

  • 暴力做法:找出最小的数,将其删除;找出次小的数,将其删除;以此类推。时间复杂度O(kn)
  • 直观做法:利用排序做法将其排序,然后直接输出第k个数。时间复杂度O(nlogn)
  • 二分做法:二分答案,设当前二分的值为mid,扫描一遍序列统计不超过mid的数的个数,设为cnt
    • kcnt:答案肯定在[l,mid]之间
    • k>cnt:答案肯定在[mid+1,r]之间
    • 时间复杂度O(nlogV)V是值域
  • 特殊做法:中位数的中位数,时间复杂度O(n)

再考虑一下另一道题目:给定一个长度为n的数列A和一个固定的整数s,执行m次操作,操作类型有两种,如下

  • 求序列A的第l个数到第r个数中不超过s的数的个数
  • 将序列A的第x个数修改为y
  • 要求单次操作的均摊复杂度为log级别

先来解决第一个操作。如果将A中不大于s的数看做1(表示对答案有1的贡献),大于s的数看做0,那么就变成了统计[l,r]的和的问题。考虑到有修改操作,我们可以使用树状数组/线段树/平衡树

再来看看第二个操作。每次修改等价于去掉了一个A[x],增加了一个y,而且都发生在x位置上。于是有

  • A[x]sadd(x,1),表示在x位置减一
  • ysadd(x,1),表示在x位置加一
  • 由于我们需要在其他时刻知道A[x]的值,所以我们还要A[x]y,从而正确维护A

这两个问题看起来没有任何的关联,那如果第一个问题是多次查询呢?

我们尝试将前面的解法结合起来。初始化时,令LA中最小的数,RA中最大的数。先将所有询问读入,采取离线做法
设当前二分区间为[L,R](这里有一个前提,我们只考虑A中在[L,R]的数,其余数全部变为0),二分值为mid,扫描每个询问i=1m,统计[li,ri]中不超过mid的数有多少个,记为ci.由于每次统计的时候,mid是一个固定的值,所以可以使用我们上面讨论的第二道题目的做法。再根据ci对查询进行分类

  • kici:第i个询问的答案在[L,mid]中。将这类询问归为第一类
  • ki>ci:第i个询问的答案在[mid+1,R]中。将这类询问归为第二类。但是注意,这里不是简单地归为第二类。与上面所讨论的第一道题目有区别,我们需要kikici

将上述的递归过程完成即可

时间复杂度分析:递归树有O(logV)层,每一层的复杂度是O((m+n)logn),所以总的时间复杂度是O((m+n)lognlogV)

思考:我们最开始举的例子的二分是不会有类似q[i].z-=cnt的操作的,如果我这里仿照开始的例子,也选择不用q[i].z-=cnt而是不改变值域,可以吗?

有了上面的例子,我们就可以知道整体二分的用途了:简单地说,可以先按照普通二分去想,发现一次二分的复杂度符合要求但是多次二分的复杂度太大了就可以把所有二分结合在一起解决,故名整体二分。更严格的要求可以去看OI-wiki

细心的同学可能发现,我们最开始举的例子,是带修的,而我们的例题却没有带修,那么整体二分可以做带修版本的例题吗?

答案当然是肯定的

这道题目就是动态查询区间第k小。借鉴静态查询区间第k小的思路,我们仍然把输入看做若干次添加。对于后面的修改操作,看成是删除加上添加。对于每个删除操作,我们将树状数组对应位置减一;对于每个添加操作,我们将树状数组对应位置加一即可

考虑一下正确性:在递归树上任意一点,任意一个查询操作,所有对其的影响一定会计入到树状数组中。分情况讨论。对于最开始的初始化操作,所有在[L,R]的操作肯定都在当前操作序列的最前面。对于后面的修改操作,如果是1标记,那么其对应的添加操作一定也在当前操作序列里面,而且在这个1操作前面,所以对于任意一个元素,既不会漏记,也不会重记(任意一个元素的操作序列一定是+1 -1 +1 -1 ... +1 -1 +1

举一个例子,假设当前值域区间为[5,10],树状数组为空。某一位数字的值是7,而且其所经过的修改为6387,那么其操作序列就是+1 -1 +1 -1 +1 -1 +1;对于当前操作序列,其包含一个子集为+1 -1 +1 -1 +1,可以知道7不会漏记

代老师让讲一下提高组综合题目,范围给的太大了,类似于“计算机导论”这种课,思来想去,就觉得讲讲今年两道真题吧,蓝色

第一题是[CSP-S 2024] 染色。做这道题目的时候是一月九号。一月十号是算法与数据结构考试,当时在想怎么复习(由于太菜一直在ACM校队边缘徘徊,只能去搞人工智能qaq,许久没搞算法竞赛导致复习思路都忘了),突然想起来要不康康现在的CSP和NOIP是什么水平(NOIP1=分数线270,CQ真是一个美好的地方),结果一看果然很有水平b( ̄▽ ̄)d。挑了一道CSP的蓝色题目做,就是DP啦。从开始做到AC一共花了一小时四十分钟(我校陈同学考场上只花了半小时,给我秒杀了),其中前一小时二十分钟实现了单log做法,其中思路一小时,代码二十分钟,结果现在CCF不让过,没办法只好优化成线性做法了

第二题是[NOIP2024] 编辑字符串。OI举办这么多年应该是第一次T1比T2难(反正我当年搞的时候做真题没有做到过)。其实也是因为T1的个体差异很大,当时NOIP考完了我看洛谷上面都要吵翻天了。我自己属于觉得这道题目比较简单的人,从开始做到AC一共花了半小时,其中思路十分钟,代码二十分钟。但我看到很多七级勾甚至有金钩的都卡了很久,果然个体差异很大┓( ´∀` )┏

posted @   最爱丁珰  阅读(4)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
点击右上角即可分享
微信分享提示