P.S.:这个星期写了一个星期的莫队,现在也差不多理解了,下周该学点别的了(其实是被long long卡得生活不能自理......快要写吐了).

在本文开始之前,先orz莫涛……

莫队算法(Mo’s algorithm),是一种离线解决区间问题的算法.
据说,只要不强制在线,莫队算法能解决所有区间查询问题……

如何判断一个问题可以使用莫队?
如果我们知道[L,R]的答案,便可以O(1)推出[L-1,R] [L,R-1] [L+1,R] [L,R+1]的答案,就可以用莫队做…

莫队算法的基本思想就是,把所有询问离线下来,得到一堆[L,R],我们已经知道上面的东西都可以O(1)求出了,那么我们对于[L2,R2L_2,R_2]的答案就可以通过[L1,R1L_1,R_1] ,花费|L2−L1|+|R2−R1||L_2-L_1|+|R_2-R_1|的时间求解….

哦 那么我们是不是就可以通过改变询问的顺序来少些重复的转移?
——嗯,没错,二维平面MST(曼哈顿距离最小生成树)!!!
莫队告诉我们,只要按这颗树做,复杂度就不会太高……而我们能在O(nlog2n)O(nlog_2n)时间内求出MST…

但这样的编程复杂度岂不是太高了?(MST对我等蒟蒻来说实在是……)
但是不要紧,我们有偷懒的办法——分块的O(nn‾√)O(n\sqrt n)还是没问题的嘛= =(当然我们假设n,q同级)
(orz 其实用MST做到最后的复杂度也是O(nn‾√)O(n\sqrt n),只是常数小了点(别问我为啥,我不会证!!))
我们把左端点的块编号作为第一关键字,把右端点的编号作为第二关键字排序…
然后按排序好的序列推过去就行了orz….

Q:为什么不是按左端点序号为第一关键字,右端点序号为第二关键字排序呢?
A:是为了避免LL略小于L1L_1略小于L2L_2,但R1R_1远小于R远小于R2R_2的情况啊……

关于复杂度的证明:
右端点:由于排过序,左端点跨块时变得多,最多变n,有n‾√\sqrt n个块所以不超过O(nn‾√)O(n\sqrt n)
左端点:由于按左端点排序,跨两块最多也不超过2n‾√2\sqrt n,有q个询问,q,n同级所以不超过O(nn‾√)O(n\sqrt n)
而实际上的复杂度应该不到这个最坏复杂度,大概就O(玄学)了…

嗯 差不多就是这样,下面我们看代码……

我们做莫队的时候就是要分析:
我们当前的区间维护到了[L,R],现在遇到了x点…
-如果x∈[L,R]中,肯定要删除(不然就不会用到x点了)
-如果x∉[L,R],我们就要添加
所以我们可以用一个bool数组来维护每个点是不是在区间中(当然这份代码没有这么写)

然后我们就需要一个fix函数来维护……

void fix(int p,int &res)    //res用于维护结果,p表示更新p点
{if(ex[p]){//TODO:删掉p点要维护什么信息}else{//TODO:添加p点要维护什么信息}ex[p]^=1; //处理完p点要将p点存在性取反...
}

处理询问是怎么推过去的呢?

//我们需要定义一个询问的结构体
struct query
{int l,r,id; //第id个问题询问[l,r]
};
//我们之前需要一个cmp函数(sort用)
bool cmp(const query &a,const query &b)
{if(a.l/blk==b.l/blk) return a.r<b.r; //blk表示分块的大小return a.l<b.l;
}void solve()
{sort(q+1,q+m,cmp); //将询问排序int l=q[1].l,r=q[1].r-1;int res=0; //[l,r]表示当前处理到的区间,res表示结果//开始的时候肯定不会想更新一堆信息所以把区间设为空for(int i=1;i<=m;i++){int L=q[i].l,R=q[i].r;while(l>L) fix(--l,res);while(l<L) fix(l++,res);while(r>R) fix(r--,res);while(r<R) fix(++r,res);//这一串记住--l,其他都能推出来,至于为什么,也是很好理解的~ans[q[i].id]=res;}
}
//基本就是这样咯~

例题? 是莫队在集训队论文中提出的.. bzoj上莫涛版权所有的一道题…
bzoj2038-小z的袜子

化式子什么的我本不想说,但是鉴于实在不是很懂orz…
所以还是要化一下的…

ans=∑C(cur[colori],2)C(r−l+1,2)ans=\frac{\sum C(cur[color_i],2)}{C(r-l+1,2)}
=∑cur[colori]!(cur−2)!∗2!(r−l+1)!(r−l−1)!∗2!= \frac{\sum \frac{cur[color_i]!}{(cur-2)!*2!}}{\frac{(r-l+1)!}{(r-l-1)!*2!}}
=∑cur[colori](cur[colori]−1)(r−l)∗(r−l+1)= \frac{\sum cur[color_i](cur[color_i]-1)}{(r-l)*(r-l+1)}
=∑cur[colori]2−∑colori(r−l)∗(r−l+1)= \frac{\sum cur[color_i]^2-\sum color_i}{(r-l)*(r-l+1)}
=∑cur[colori]2+(r−l+1)(r−l)∗(r−l+1)= \frac{\sum cur[color_i]^2+(r-l+1)}{(r-l)*(r-l+1)}

应该能看懂吧= = coloricolor_i表示i的颜色,cur[i]表示当前颜色为i的节点有多少…

然后根据上面,我们就能得出这样代码:

//此题极限数据50000*50000 一定要开long long
//开long long的时候每一处乘法都要记得强转long long(WA惨的教训)
#include <cmath>
#include <cstdio>
#include <algorithm>
using namespace std;
const int N=50005;
typedef long long int64;int c[N],ex[N];
int64 cur[N];
int n,m,blk;struct _ans{int64 a,b;
}ans[N];    //这题答案是个分数...
struct query{int l,r,id;
}q[N]; int ttt;
bool cmp(const query &a,const query &b){if(a.l/blk==b.l/blk) return a.r<b.r;return a.l<b.l;
}
inline void buildquery(int l,int r,int id){q[id].l=l; q[id].r=r; q[id].id=id;
}inline int getnum(){int a=0;char c=getchar();bool f=0;for(;(c<'0'||c>'9')&&c!='-';c=getchar());if(c=='-') c=getchar(),f=1;for(;c>='0'&&c<='9';c=getchar()) a=(a<<1)+(a<<3)+c-'0';if(f) return -a; return a;
}
int64 gcd(int64 a,int64 b){if(!b) return a;return gcd(b,a%b);
}void fix(int p,int64 &res){if(ex[p]){res-=(cur[c[p]]<<1)-1;//这里是化了一下式子之后简便的位运算版(利用完全平方公式,可以自己推一下)cur[c[p]]--;}else{res+=(cur[c[p]]<<1|1); //同上cur[c[p]]++;}ex[p]^=1;
}
void solve(){sort(q+1,q+m+1,cmp);int l=q[1].l,r=q[1].l-1; int64 res=0;for(int i=1;i<=m;i++){int L=q[i].l,R=q[i].r,id=q[i].id;while(l>L) fix(--l,res);while(l<L) fix(l++,res);while(r<R) fix(++r,res);while(r>R) fix(r--,res);if(L==R) ans[id].a=0,ans[id].b=1; //特殊情况特殊处理else{int64 a=res-(r-l+1),b=(int64)(r-l+1)*(r-l),k=gcd(a,b);ans[id].a=a/k,ans[id].b=b/k;}}
}int main(){n=getnum(),m=getnum(); blk=sqrt(n);for(int i=1;i<=n;i++) c[i]=getnum();for(int i=1;i<=m;i++){int x=getnum(),y=getnum();buildquery(x,y,i);} solve();for(int i=1;i<=m;i++) printf("%lld/%lld\n",ans[i].a,ans[i].b);
}

就这样= = 完结撒花= =

【笔记篇】莫队算法(一)相关推荐

  1. 【学习笔记】莫队算法

    莫队算法 确实是看过的最良心的讲解: https://www.cnblogs.com/CsOH/p/5904430.html 问题:有n个数组成一个序列,有m个形如询问L, R的询问,每次询问需要回答 ...

  2. 【算法竞赛学习笔记】莫队算法-超优雅的暴力算法

    title : 莫队算法 tags : ACM,暴力 date : 2021-10-30 author : Linno 普通莫队 常用操作:分块/排序/卡常/离散化等,直接上板子. luoguP270 ...

  3. BZOJ 2038: [2009国家集训队]小Z的袜子(hose)【莫队算法裸题学习笔记】

    2038: [2009国家集训队]小Z的袜子(hose) Time Limit: 20 Sec  Memory Limit: 259 MB Submit: 9894  Solved: 4561 [Su ...

  4. 莫队算法学习笔记(二)——带修莫队

    前言:什么是莫队 莫队算法,是一个十分优雅的暴力. 普通的莫队可以轻松解决一些离线问题,但是,当遇上了一些有修改操作的问题,普通莫队就无能为力了. 于是,改进后的莫队--带修莫队就这样产生了. L i ...

  5. NBUT 1457 Sona(莫队算法+离散化)

    [1457] Sona 时间限制: 5000 ms 内存限制: 65535 K 问题描述 Sona, Maven of the Strings. Of cause, she can play the ...

  6. C++ 莫队算法(转)

    胡小兔的良心莫队教程:莫队.带修改莫队.树上莫队 在开始学习莫队之前,照例先甩一道例题:BZOJ 1878 HH的项链. 题意:求区间内数的个数,相同的数只算一次. 在我关于这道题的上一篇题解中,我使 ...

  7. 【清橙 A1206】小Z的袜子(莫队算法)

    [清橙 A1206]小Z的袜子(莫队算法) A1206. 小Z的袜子 时间限制:1.0s   内存限制:512.0MB   总提交次数:1144   AC次数:319   平均分:43.15 将本题分 ...

  8. 曼哈顿距离最小生成树莫队算法

    参考资料:https://www.cnblogs.com/CsOH/p/5904430.html https://blog.csdn.net/huzecong/article/details/8576 ...

  9. NBUT 1457 Sona 莫队算法 分块处理

    [1457] Sona 时间限制: 5000 ms 内存限制: 65535 K 问题描述 Sona, Maven of the Strings. Of cause, she can play the ...

最新文章

  1. android项目获得所有运行程序
  2. 跨平台C++开源码的两种经常使用编译方式
  3. Kibana安装及简单使用
  4. 初识Lucene.net
  5. orcle 删除表报正在使用_oracle 删除表空间错误 提示:ora-02429:无法删除用于强制唯一/...
  6. The value of a feed cannot be a tf.Tensor object.
  7. sdh管理单元指针_SDH设备上STM-1接口是啥玩意
  8. html5上传视频和预览,HTML5 上传前预览
  9. 话说关于 ZooKeeper 方面,面试有什么可问的啊?​
  10. graphics2d 乱码 java_java Graphics2D绘制文字并居中并解决服务器乱码问题
  11. jquery pager 访问 java_基于JQuery的Pager分页器实现代码
  12. 转I give the orders around here.
  13. spark 通过打散热点key解决数据倾斜问题
  14. redis java 下载_linux系统下安装redis以及java调用redis
  15. 韩顺平 jdbc 之 mysql,(韩顺平讲解)jdbc学习(四)---java连接mysql
  16. 开始使用Mac OS X——致Mac新人
  17. vmware,qemu各种方式上网设置(转)
  18. 转载:“凤求凰”的解释,有才
  19. 日期转农历日期的一个插件
  20. Raft 算法 详细版介绍

热门文章

  1. 我做分析师的十年感受 ( 三 )
  2. java 转发与重定向_Java 转发和重定向的区别
  3. 推荐上百个github上Python爬虫案例
  4. 怎么在html上放音乐,教你如何在网页中直接播放MP3音乐
  5. Docker入门(1)--Win11下Docker配置
  6. [经验教程]华为H6子母路由器一拖三怎么配置安装组网覆盖客厅餐厅和卧室?
  7. springboot的应用(springboot+定时任务+发邮件)
  8. android 通过adb发送广播
  9. 【MATLAB 的cdfplot函数】
  10. matlab帮助入口