【算法学习】莫队
1.【算法学习】排序2.【算法学习】Manacher 马拉车3.【算法学习】KMP 算法4.LCA 最近公共祖先(树链和倍增)这次真有树链了!!!5.线段覆盖问题6.【算法学习】学换根dp有感7.二分图最大匹配8.【算法学习】01BFS9.洛谷 P1892 [BOI2003] 团伙 种类并查集 扩展域并查集10.【算法学习】高斯消元法11.贝叶斯公式12.背包13.【算法学习】模拟退火14.【算法学习】基环树15.【算法学习】树链部分
16.【算法学习】莫队
17.【算法学习】分块九讲18.平衡树19.圆方树20.【算法学习】点分治21.公式22.【算法学习】笛卡尔树23.【算法学习】悬线法24.欧几里得算法与 EX25.【算法学习】逆元与求解26.【算法学习】费马定理27.三分28.裴蜀定理29.【算法学习】欧拉函数φ30.【算法学习】二维转一维问题31.【算法学习】扫描线32.【算法学习】矩阵乘法33.【算法学习】同余最短路34.【算法学习】组合数学35.【算法学习】反悔贪心开幕雷击!我既然都贴上了大佬的博客,那还要我有什么用,但是我要是不记录的话早晚会忘,那既然是给自己看的话就象征性地写一下吧,等以后熟练了也不需要这博客了。
莫队虽然用到了分块,但是并不对分块进行操作,而是对分块的性质进行运用。
普通莫队
P1972 [SDOI2009] HH的项链
非常模板的题,但是卡莫队,所以自己去讨论区找双倍经验吧。
莫队是怎么一回事呢,我们把所有的询问都离线地储存下来,然后用 \(l,r\) 指针在数列上移动,在移动的过程中处理答案,在指针移动到查询区间时就储存当前答案,而这个查询区间的选择就很重要了,我们讲每个端点都分到不同的块内,对所属的块进行左端点排序,这样复杂度就降到了 \(O(n\sqrt{n})\)。(我不想证了 其实是不会)
优化
排序奇偶性优化,当查询区间左端点在同一块内,判断所在的块是奇数就按右端点从小到大排序,是偶数就按从大到小排序,这样的话相当于是一个来回,可以很好地节约时间。
#include <bits/stdc++.h> #define int long long using namespace std; const int N=1e6+19; int n,m; int a[N]; int of[N]; int len; int ans[N]; int cnt[N]; int now=0; struct ss{ int l,r,id; }q[N]; bool cmp(ss g,ss h){//奇偶数排序 return (of[g.l]^of[h.l])?of[g.l]<of[h.l]:(of[g.l]&1)?g.r<h.r:g.r>h.r; } void add(int pos){ if(!cnt[a[pos]]++) ++now; } signed main(){ ios::sync_with_stdio(false); cin>>n>>m; len=sqrt(n);//分块 for(int i=1;i<=n;i++){ of[i]=(i-1)/len+1; } for(int i=1;i<=n;i++){ cin>>a[i]; } for(int i=1;i<=m;i++){ cin>>q[i].l>>q[i].r; 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,pr=q[i].r; //移动指针 while(l<ql) now-=!--cnt[a[l++]]; while(l>ql) now+=!cnt[a[--l]]++; while(r<pr) now+=!cnt[a[++r]]++; while(r>pr) now-=!--cnt[a[r--]]; ans[q[i].id]=now; } for(int i=1;i<=m;i++){ cout<<ans[i]<<"\n"; } return 0; }
带修莫队
通常情况下因为莫队是离线处理所以通常是不支持修改的,但如果并不强制修改的话,只是简单的修改的话带修莫队是可以实现的。
P1903 [国家集训队] 数颜色 / 维护队列
在上一题的基础上增加了单点修改操作,我们增加一个时间戳,对于每次修改都增加时间,每次询问都也储存一个时间戳,我们在移动指针时也要把时间移到查询区间的时间戳上,对应的数列上的数也要更换,答案也要更新。
跟上面代码差别不大,这种暴力算法好处就是写着简单。
注意点细节,注意块长取 \(n^{\frac{2}{3}} (\sqrt[3]{n^2})\),什么?要证明?没有。
#include <bits/stdc++.h> #define int long long using namespace std; const int N=5e5+10; int n,m; int a[N]; struct ss{ int l,r,t,id; }q[N]; int qc=0; int ct[N]; int cpos[N]; int c[N]; int cnt[N]; int ans[N]; int of[N]; int cc=0; int len; bool cmp(ss g,ss h){ return (of[g.l]^of[h.l])?of[g.l]<of[h.l]:(of[g.r]^of[h.r])?of[g.r]<of[h.r]:g.t<h.t; } signed main(){ ios::sync_with_stdio(false); cin>>n>>m; len=pow(n,2.0/3.0); for(int i=1;i<=n;i++){ of[i]=(i-1)/len+1; } for(int i=1;i<=n;i++){ cin>>a[i]; } for(int i=1;i<=m;i++){ char op; int l,r; cin>>op>>l>>r; if(op=='Q'){ qc++; q[qc].l=l; q[qc].r=r; q[qc].t=cc; q[qc].id=qc; } else{ cc++; cpos[cc]=l; ct[cc]=r; } } sort(q+1,q+1+qc,cmp); int l=1,r=0,now=0,time=0; for(int i=1;i<=qc;i++){ int ql=q[i].l,pr=q[i].r,qt=q[i].t; while(l<ql) now-=!--cnt[a[l++]]; while(l>ql) now+=!cnt[a[--l]]++; while(r>pr) now-=!--cnt[a[r--]]; while(r<pr) now+=!cnt[a[++r]]++; while(time>qt){ if(ql<=cpos[time]&&cpos[time]<=pr){ now-=!--cnt[a[cpos[time]]]-!cnt[ct[time]]++; } swap(a[cpos[time]],ct[time]); time--; } while(time<qt){ time++; if(ql<=cpos[time]&&cpos[time]<=pr){ now-=!--cnt[a[cpos[time]]]-!cnt[ct[time]]++; } swap(a[cpos[time]],ct[time]); } ans[q[i].id]=now; } for(int i=1;i<=qc;i++){ cout<<ans[i]<<"\n"; } return 0; }
例题练习
普通莫队
P1494 [国家集训队] 小 Z 的袜子 莫队板子题,运用一些数学知识就可以解决。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek “源神”启动!「GitHub 热点速览」
· 我与微信审核的“相爱相杀”看个人小程序副业
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 如何使用 Uni-app 实现视频聊天(源码,支持安卓、iOS)
· C# 集成 DeepSeek 模型实现 AI 私有化(本地部署与 API 调用教程)