普通、带修(可持久化)莫队算法入门例题详解

本文详细介绍了莫队算法,包括普通莫队和带修莫队。以2038: 小Z的袜子和2120: 数颜色为例,讲解了如何应用莫队算法解决区间概率计算和颜色计数问题。文章强调了莫队算法的离线处理、分块思想和时间复杂度优化,并指出其适用条件。
摘要由CSDN通过智能技术生成

目录

【莫队算法】

【普通莫队】

【代码】

【题面】

【带修莫队】

【代码】

【题面】

【总结】


 

【莫队算法】

参考大米饼的莫队算法 ,目前的题型概括为三种:普通莫队,带修莫队以及树形莫队。

【普通莫队】

例题:2038: [2009国家集训队]小Z的袜子(hose)

题意:给定编号1-n的n只袜子的颜色,输出从询问的区间[L,R]中随机抽出两只袜子颜色相同的概率。

首先考虑对于一个长度为n区间内的答案如何求解。

题目要求Ans使用最简分数表示:那么分母就是n*(n-1)->表示两两袜子之间的随机组合,分子是每种颜色可能配对情况的累加和,即该区间内每种颜色i出现次数sum[i]*(sum[i]-1)。

莫队算法的思路是,离线情况下对所有的询问进行一个美妙的SORT(),然后两个指针l,r(本题是两个,其他的题可能会更多)不断以看似暴力的方式在区间内跳来跳去,最终输出答案。

掌握一个思想基础:两个询问之间的状态跳转。

当前完成的询问的区间为[a,b],下一个询问的区间为[p,q],现在保存[a,b]区间内的每个颜色出现次数的sum[]数组已经准备好,[a,b]区间询问的答案Ans1已经准备好,怎样用这些条件求出[p,q]区间询问的Ans2?

考虑指针向左或向右移动一个单位,我们要付出多大的代价才能维护sum[]和Ans(即使得sum[],Ans保存的是当前[l,r]的正确信息)。

我们对图中a,b的向右移动一格进行分析: 

a指针向右移动一个单位,所造成的后果就是:我们损失了一个i颜色的方块,那么我们要怎样维护呢?sum[i]-1即可。那Ans如何维护呢?分母从n*(n-1)变成(n-1)*(n-2),而分子中的其他颜色对应的部分是不会变的,故我们只需要修改答案中颜色为i的可能情况即可,即Ans-以前该颜色的答案贡献+现在的答案贡献。同理,b指针移动也是差不多的。

回归正题,我们发现知道一个区间的信息,要求出旁边区间的信息(旁边区间指的是当前区间的一个指针通过加一减一得到的区间),竟只需要O(1)的时间。

就算是这样,到这里为止的话莫队算法依旧无法焕发其光彩,原因是:如果我们以读入的顺序来枚举每个询问,每个询问到下一个询问时都用上述方法维护信息,那么在你脑海中会浮现出l,r跳来跳去的疯狂景象,疯狂之处在于最坏情况下时间复杂度为:O(n2) — 如果要这样还不如写一个暴力程序。

“莫队算法巧妙地将询问离线排序,使得其复杂度无比美妙……”。在一般做题时我们时常遇到使用排序来优化枚举时间消耗的例子。莫队的优化基于分块思想:对于两个询问,若在其l在同块,那么将其r作为排序关键字,若l不在同块,就将l作为关键字排序。这里使用Be[i]数组表示i所属的块是谁。

bool cmp(Mo a,Mo b){return Be[a.l]==Be[b.l]?a.r<b.r:a.l<b.l;}

值得强调的是,我们是在对询问进行操作。

时间复杂度分析(分类讨论思想):

首先,枚举m个答案,就一个m了。设分块大小为unit。

分类讨论:

①l的移动:若下一个询问与当前询问的l所在的块不同,那么只需要经过最多2*unit步可以使得l成功到达目标,复杂度为:O(m*unit)

②r的移动&

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值