一、理解

我的理解就是巧妙的暴力,利用双指针以及分块思想,巧妙的移动双指针,时间复杂度可以达到O(NlogN)

强推博客:写的又好又全。链接

二、套路

1、普通莫队

【1】核心代码

bool cmp(node a,node b){return belong[a.l]==belong[b.l]? a.r<b.r:belong[a.l]<belong[b.l];
}
sort(q+1,q+1+m,cmp);
int l=1,r=0;
for(int i=1;i<=m;i++){int ql=q[i].l,qr=q[i].r;while(l<ql) del(l++);while(l>ql) add(--l);while(r<qr) add(++r);while(r>qr) del(r--); ans[q[i].id]=cnt;
}

add和del函数随机应变,一般都是加入或删除一个数对答案的影响。证明一下复杂度吧,便于理解代码。

(1)对左指针L,假设一个块内有x个询问,每次L最多移动次,加起来为;对于不同块之间的L,跨越一个块L最多移动次,总共可能跨n次,为

(2)对于右指针R,对于不同块之间的R,它是无序的,最多移动n次,有块,为;块内的R有序,R最多移动次,总共块,为

因此总体为,有常数。

【2】例题及题解(从易到难)

(1)luogu SP3267 DQUERY - D-query      题解

(2)luogu P1972 [SDOI2009]HH的项链      题解

(3)luogu P2709 小B的询问      题解

(4) CodeForces - 86D Powerful array      题解

(5)luogu P1494 [国家集训队]小Z的袜子      题解

(6)luogu P3709 大爷的字符串题       题解

(7)CodeForces - 617E XOR and Favorite Number      题解

2、带修莫队

【1】核心代码

bool cmp(node a,node b){return (be[a.l]^be[b.l])?be[a.l]<be[b.l] :(be[a.r]^be[b.r]) ? be[a.r]<be[b.r] : a.tim<b.tim;
}
blcok=ceil(pow(1.0*n,2.0/3.0));//注意这里要变为n^(2/3)
int l=1,r=0,ti=0;
while(l<ql) del(l++);
while(l>ql) add(--l);
while(r<qr) add(++r);
while(r>qr) del(r--);
while(ti<qt){++ti;if(ql<=b[ti].pos&&b[ti].pos<=qr)del(b[ti].pos);swap(a[b[ti].pos],b[ti].col);if(ql<=b[ti].pos&&b[ti].pos<=qr)add(b[ti].pos);
}
while(ti>qt){if(ql<=b[ti].pos&&b[ti].pos<=qr)del(b[ti].pos);swap(a[b[ti].pos],b[ti].col);if(ql<=b[ti].pos&&b[ti].pos<=qr)add(b[ti].pos);--ti;
}

对于带修莫队,我们需要给每一个询问加一个时间戳,时间戳的取值就是之前最近的修改。排序时,先按左边界的块,再按右边界的块,最后按时间戳。先移动左右指针,然后再考虑修改

如果时间戳大了,说明我们改多了,我们需要再改回去改的时候,要考虑是否对答案造成影响

如果时间戳小了,说明我们改少了,要改到询问所在的时间戳,改的时候,要考虑是否对答案造成影响

使用swap可以方便地进行修改。(具体看上面代码)

注意:有的dalaodalao证明了当块的大小设时理论复杂度达到最优。不过可以证明,块大小取优于取的情况,总体复杂度。而块大小取时会退化成,不建议使用。(出处

【2】例题及题解

(1)luogu P1903 [国家集训队]数颜色 / 维护队列     题解

(2)HDU - 6610 Game      题解

(3)luogu P4074 [WC2013]糖果公园 【树上带修莫队有难度】      题解

3、树上莫队

【1】核心代码

bool cmp(Node a,Node b){return (be[a.l]^be[b.l]) ? be[a.l]<be[b.l] : (be[a.l]&1) ? a.r<b.r : a.r>b.r;
}
int fir[N],la[N],dfn[N<<1],tot=0;
int dep[N],f[N][30];
void dfs(int u,int fa){fir[u]=++tot;dfn[tot]=u;for(int i=1;i<=20;++i)f[u][i]=f[f[u][i-1]][i-1];for(int i=head[u];~i;i=g[i].nex){int v=g[i].to;if(dep[v]||v==fa) continue;dep[v]=dep[u]+1;f[v][0]=u;dfs(v,u);}la[u]=++tot;dfn[tot]=u;
}
int getLca(int x,int y){if(dep[x]<dep[y]) swap(x,y);int dis=dep[x]-dep[y];for(int i=20;i>=0;--i)if(dis&(1<<i))x=f[x][i];if(x==y) return x;for(int i=20;i>=0;--i)if(f[x][i]!=f[y][i])x=f[x][i],y=f[y][i]; return f[x][0];
}
void change(int x){x=dfn[x];vis[x] ? del(x) : add(x);vis[x]^=1;
}
for(int i=1;i<=m;++i){int u,v;//scanf("%d%d",&u,&v);u=read(),v=read();if(fir[u]>fir[v]) swap(u,v);int lca=getLca(u,v);if(lca==u)q[i].l=fir[u];elseq[i].l=la[u],q[i].lca=lca;;q[i].r=fir[v];q[i].id=i;
}
sort(q+1,q+1+m,cmp);
int l=1,r=0;
for(int i=1;i<=m;i++){int ql=q[i].l,qr=q[i].r,lca=q[i].lca;   while(l<ql) change(l++);while(l>ql) change(--l);while(r<qr) change(++r);while(r>qr) change(r--);ans[q[i].id]=sum;if(lca && !num[a[lca]]) ++ans[q[i].id];
}

这里需要了解欧拉序(强推博客),利用欧拉序,就可以把树上的路径转化为连续区间的问题。

这里还要求lca。对于树上u到v的路径,设first[u]<first[v],

如果lca(u,v)==u,对应欧拉序的连续区间就为[ first[u] , first[v] ] ;

否则, 对应欧拉序的连续区间就为[ last[u] , first[v] ] , 不过还要加上 lca(u,v) 。

要注意的是区间中出现两次的点并不在u到v的路径中,所以我们需要一个vis数组,每次进行异或操作。根据vis[i],进行删除操作/添加操作。

一定记得有的数组需要开2*n并且别忘了加lca的贡献 !!!!!!!!

【2】例题及题解

(1)luogu SP10707 COT2 - Count on a tree II​​​​​​​      题解

(2)luogu P4074 [WC2013]糖果公园​​​​​​​ 【树上带修莫队有难度】     题解

4、不删除莫队

【1】核心代码

bool cmp(node a,node b){return (be[a.l]^be[b.l]) ? be[a.l]<be[b.l] : a.r<b.r;
}
block=ceil(sqrt(1.0*n));
bnum=ceil(1.0*n/block);
for(int i=1;i<=bnum;i++){bl[i]=br[i-1]+1,br[i]=br[i-1]+block;for(int j=bl[i];j<=br[i];j++)be[j]=i;
}
for(int i=1;i<=m;i++)scanf("%d%d",&q[i].l,&q[i].r),q[i].id=i;
sort(q+1,q+1+m,cmp);
int pos=1;
ll sum;
for(int i=0;i<=bnum;i++){sum=0;memset(cnt,0,sizeof cnt);int l=br[i]+1,r=br[i];for(;be[q[pos].l]==i;pos++){int ql=q[pos].l,qr=q[pos].r;if(be[ql]==be[qr]){ll temp=0;for(int j=ql;j<=qr;j++) cnt1[mp[a[j]]]=0;for(int j=ql;j<=qr;j++){++cnt1[mp[a[j]]];temp=max(1LL*a[j]*cnt1[mp[a[j]]],temp) ;}ans[q[pos].id]=temp;               continue;}while(r<qr){++r;++cnt[mp[a[r]]];sum=max(sum,1LL*a[r]*cnt[mp[a[r]]]); }ll temp=sum;while(l>ql){--l;++cnt[mp[a[l]]];sum=max(sum,1LL*a[l]*cnt[mp[a[l]]]);                 }ans[q[pos].id]=sum;while(l<br[i]+1){--cnt[mp[a[l]]];l++;}sum=temp;}
}

对于普通莫队,我们一般考虑添加和删除只是顺序变一下,但有的题删除操作根本没办法维护需要的东西。

这时,不删除莫队就可以大显神威了,删除太难了,那我们不删除,只添加就好了。

现在考虑怎么不删除,我们排序时,对于左端点在同一个块内的询问他们的r是从小到大有序的,那么我们可以利用这个特点,一个块一个块的计算询问区间

对于左端点在同一个块内的询问:

首先考虑,如果询问区间的左右端点(ql、qr)都在一个块内,那我们直接暴力计算,复杂度为,最多m个询问区间的左右端点(ql、qr)都在一个块内,复杂度为

否则,我们保持r有序,那么对于左端点一个块内的询问,r最坏从头到尾遍历一遍为,总共块,复杂度也为

对于每个询问,我们现在只要移动l即可,l最多移动次,最多m个询问区间,

总体复杂度

对于块i中的询问,将l和r初值置为l=br[i]+1,r=br[i]即可。

注意,对于l移动时,带来的修改只对当前询问有关,所以改了要再改回去,有时还要维护两组状态。

注意,这里还有个块0需要带着。

【2】例题及题解

(1)luogu AT1219 歴史の研究​​​​​​​     题解

(2)luogu SP3267 DQUERY - D-query      题解

(3)luogu P5906 【模板】回滚莫队&不删除莫队​​​​​​​      题解

三、最后一题

树上带修莫队,检验一下自己吧。

luogu P4074 [WC2013]糖果公园​​​​​​​      题解

参考且强推博客:https://www.cnblogs.com/WAMonster/p/10118934.html

莫队算法(普通莫队、带修莫队、树上莫队、不删除莫队)学习笔记【理解+套路/核心代码+例题及题解】相关推荐

  1. [算法学习]模拟退火算法(SA)、遗传算法(GA)、布谷鸟算法(CS)、人工蜂群算法(ABC)学习笔记---附MATLAB注释代码

    目录 1.模拟退火算法(Simulated Annealing,SA) 1.1 本质: 1.2 算法思想 1.3 SA流程图 1.4 模拟退火过程 1.5 SA解决TSP问题 1.6 SA改进方向 1 ...

  2. 《用莫比乌斯带巧解内接矩形问题:拓扑学的用处》学习笔记

    昨天 Rocket101 孟美岐 发歌了,刚刚看到,犹豫了一会磕不磕.最后含是氪了一发,唱的含行,可惜旋律一般好听,没有加入歌单. Bilibili链接 用莫比乌斯带巧解内接矩形问题:拓扑学的用处.- ...

  3. 数学建模各类算法学习笔记(附matlab代码)

    目录 插值和拟合 线性规划 综合评价1:层次分析法(Analytic Hierarchy Process)AHP 综合评价2:Topsis(优劣解距离法) 最优解问题1:遗传算法Genitic alg ...

  4. 带避障功能的MPC局部路径规划+跟踪控制学习笔记

    目录 1 轨迹跟踪MPC设计 1.1 非线性模型预测控制算法 1.1.1 非线性MPC概述 1.1.2 基于动力学的车辆点质量模型(非线性.连续) 1.1.3 离散化为预测模型 1.1.4 避障功能函 ...

  5. java算法优化_Java学习笔记---Java简单的代码算法优化(例)

    例:用一张1元纸币兑换1分.2分.5分硬币,要求兑换50枚硬币,求出所有组合. package mypackage01; public class demo { public static void ...

  6. 牛客练习赛85 数学家的迷题 (带修莫队/线段树)

    题意: 1:将a[id]a[id]a[id]的值改为xxx. 2:令t=a[l]×a[l+1]×...×a[r−1]×a[r]t=a[l]×a[l+1]×...×a[r−1]×a[r]t=a[l]×a ...

  7. LG P4074 [WC2013] 糖果公园(带修莫队,树上莫队)

    LG P4074 [WC2013] 糖果公园 Solution 树上带修莫队,主要还是复习带修莫队和树上莫队. 带修莫队: 带修莫队要先对lll分块的序号作为第一关键字,对rrr分块的序号作为第二关键 ...

  8. P1903 数颜色 (带修莫队)

    题目传送门 ~~~ 题目大意 给一个有 n 个元素的数组 a,有 m 次操作,操作如下: Q 操作,询问区间 (l, r) 不同元素的个数 R 操作,把第 x 个元素修改为 y 对于每次 Q 操作,输 ...

  9. 分治 —— 莫队算法

    [概述] 莫队算法(mo's algorithm)是用来解决离线区间不修改询问问题,可以将复杂度优化到 O(n^1.5),除去普通的莫队算法外,还有带修改的莫队.树上莫队等等. 莫队常用于维护区间答案 ...

最新文章

  1. vba给服务器发送消息,使用VBA实现发邮件功能
  2. 实现数据排序的几种方法
  3. java 内存溢出 内存泄露_JVM——内存泄漏与内存溢出
  4. 递归算法介绍及Java应用实战
  5. mysql 定期删除表中无用数据
  6. 递归法:求n个元素的全排列
  7. 在 Google 工作是什么体验?
  8. php json替换,php解决json中中文部分被替换为unicode编码
  9. modelica语言学习记录V1.0
  10. markdown 设置目录跳转的简单方法
  11. [ctfshow 2021摆烂杯] FORENSICS部分 writeup
  12. docker安装,阿里云镜像配置
  13. mongodb数据库添加账号
  14. 牛顿法和高斯牛顿法对比
  15. 判断手机浏览器终端设备
  16. Java 知识点整理-7.StringBuffer类+冒泡排序+选择排序+二分法+Arrays类+基本数据类型的包装类
  17. 不同的 docker-compose 间怎么实现网络互通
  18. 中兴通讯能制造服务器吗,中兴通讯服务器搭载“黑匣子”功能,让故障无处遁形...
  19. 苹果库乐队怎么玩_自制手机铃声(苹果)
  20. 力扣解题思路:位运算系列

热门文章

  1. 河南的抗疫英雄,给出一系列抗疫英雄的姓名和来自的省份,现在请你帮忙统计来自河南的抗疫英雄有多
  2. 我喜欢的一篇关于家庭教育的文章
  3. 和平精英吃鸡捏脸数据助手微信小程序源码
  4. jsp表单提交中文乱码的解决
  5. 反爬虫SSL TLS指纹识别和绕过JA3算法.md
  6. fabric-ca-client 详解动态添加组织
  7. Wireshark抓取网易音乐的下载地址
  8. 设计师必备的导航网站
  9. ehvierwer登录与不登录_【虎嗅早报】抖音回应无法用微信账号登录:不清楚是否为人为...
  10. uniapp文档常用整理