浅析莫队算法

朴素的莫队算法,它的核心理论个人认为是 分块 + 双指针 + 贪心思想,一般都是用来解决线段树所不能解决的区间问题(例如不区间众数等不满足区间加法的问题)。

一般题型像这样:

给出一个 n 长的序列,然后让你维护这个序列的特定值,再给你 q  个询问,求解这 q 个询问,这些询问的形式就是给你一个区间l,r。

一个简单的思路我们很容易想到,我们对这些询问区间进行排序(按 l 为第一关键字,r 为第二关键字),然后先算出第一个询问区间,再在接下来的区间中递增微调双指针l , r,对应的修改第一次求出来的值,按照这种方法依次求得多个区间的值。这样按理来说是可以的,但是当多个区间的 l 值相差不大,而相邻两个区间的 r 相差大这就造成了复杂度与n方基本无差的情况

为了解决这个问题我们将序列分块,也就是说将 l 邻近的值按 r 排序,这样就可以解决邻近块 r 的跨度较大的问题了,一般我们是划分出\sqrt{n}块,那么同样的在每一块里也就有\sqrt{n}个元素,这样一来我们每一块微调的 l 指针的偏移量为\sqrt{n},而排序后的r 的偏移量也就很容易想到最多为 n 了,那么总复杂度也就为 o(n * \sqrt{n} + m * \sqrt{n} )  = o(max(n * \sqrt{n},m * \sqrt{n})).(n 为总长,m为询问数)

po:

#include<bits/stdc++.h>
using namespace std;
 typedef long long ll;
int main()
{
      int l = 0 , r = 1;
      for(int i = 0 ; i < m ; ++ i)
       {
  
             while(l < a[i].l) upd(a[i],-1),l++;
              while(l > a[i].l) upd(a[i],1) l--;
               while(r < a[i].r) upd(a[i],1)r++;
                 while(r > a[i].r) upd(a[i],-1) r--;/*微调左右区间指针,
并且更新当前段的保留信息,即得到当前区间*/
                 /*
                 *....根据题意和当前段的信息更新答案
                 */
       }
 }

持久化莫队:

如名,朴素化的莫队只支持纯粹的离线化解题,若我们有时需要单点修改值的时候,莫队算法该如何使用呢?

给询问的区间节点多加一个维度,表示它的修改时间,那么对于一个区间的排序我们就以它作为第三关键字,起的作用与前两关键字类同,对于修改时间,若当前询问区间的修改时间大于游动的时间指针,那么我们就把已经修改过的值一一修改回去,反之则全部修改为对应值

po:

#include<bits/stdc++.h>
using namespace std;
 typedef long long ll;
int main()
{
      int l = 0 , r = 1,time = 0;
      for(int i = 0 ; i < m ; ++ i)
       {
         while(time < a[i].time) change(++time,1);
          while(time > a[i].time) change(--time,0);/*将当前时间戳游动到合适的位置,
并选择是改回原来的样子还是修改成待修改的样子*/
             while(l < a[i].l) upd(a[i],-1),l++;
              while(l > a[i].l) upd(a[i],1) l--;
               while(r < a[i].r) upd(a[i],1)r++;
                 while(r > a[i].r) upd(a[i],-1) r--;/*微调左右区间指针,并且更新当前段的保留信息,即得到当前区间*/
                 /*
                 *....根据题意和当前段的信息更新答案
                 */
       }
 }

回滚莫队:

有时候莫队这种为当前区间增值更新或者减值更新时,很难满足某些题目的要求,比如区间最值。

为了解决这个问题,有人就提出了回滚的这种思想,对于在一块的 l和r我们可以直接暴力计算,不在同一块的l,r那就按 l 所在的块处理这个块的所有询问区间,然后让 r 一直往后扩大并保留当前 l 的状态,在处理下一个区间的时候由上一个保留的状态还原当前区间状态再回到起点(这个块的右端点)重新跑 l。当前块处理结束后,进入下一个块,清空莫队,初始化对应 l , r再次回滚。这个是对应与难减易增的,还有一种难增易减,是一种逆向思维,使 r 始终在最右边,然后回滚 r。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
差分进化算法(Differential Evolution,DE)是一种基于种群的随机搜索算法,具有以下优缺点: 优点: 1. 高效性:DE算法具有良好的全局搜索能力和快速的收敛速度,尤其在高维问题中表现较为出色。 2. 简单易实现:DE算法的思路简单,易于理解和实现,且不需要对目标函数进行任何假设或限制。 3. 对初始值不敏感:DE算法对初始值不敏感,能够在不同的初始值下得到相似的优化结果。 4. 适用性广泛:DE算法适用于多种优化问题,如函数优化、组合优化、机器学习等领域,具有广泛的应用前景。 缺点: 1. 参数设置困难:DE算法中需要设置种群大小、变异因子、交叉概率等多个参数,参数选择对算法效果具有较大的影响,需要进行反复试验和调整。 2. 易陷入局部最优:DE算法在搜索过程中可能会陷入局部最优解,特别是在目标函数具有多个峰值或存在大量噪声时。 3. 算法复杂度高:DE算法的计算复杂度较高,需要进行大量的重复计算和比较操作。 4. 需要大量的迭代次数:DE算法需要进行大量的迭代计算,因此在处理大规模问题时,计算时间会比较长。 综上所述,DE算法具有高效性、简单易实现、适用性广泛等优点,但也存在参数设置困难、易陷入局部最优、算法复杂度高、需要大量的迭代次数等缺点。需要根据具体问题的特点和要求,选择合适的优化算法进行求解。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值