zoukankan      html  css  js  c++  java
  • 莫队算法(离线)

    何谓莫队算法

    莫队算法是莫涛队长发明的,为表示对他的尊敬,故称这种算法叫莫队。


    适用范围

    一种处理序列操作的离线算法,适用范围广,复杂度一般带根号。


    莫队算法的思路

    假设题目不涉及修改操作。

    将所有操作离线,将所有操作进行二元组排序,第一维是左端点所在块的编号,第二维是右端点。

    排序后,按照顺序处理询问,维护一个双端队列,同时维护队列内区间的答案,每次从$[L,R]$的答案,扩展到$[L-1,R]$ $[L,R-1]$ $[L+1,R]$ $[L,R+1]$的答案,最终得到当此询问区间的答案。


    时间复杂度分析

    假设序列长度为$n$,询问数为$m$,分块块长为$d$,那么左端点在同一块内时,左端点移动每次不超过$d$,右端点总共移动不超过$n$,显然是$Theta (m imes d+frac{n^2}{d})$,令$d=sqrt{n}$,$n,m$同阶,则时间复杂度为$Theta(nsqrt{n})$,常数很大。


    莫对算法的本质

    莫队算法的精髓在于,离线的情况下,通过调整询问与修改间的顺序,由已知的答案扩展到未知的答案,以优秀的计算顺序换取优秀的时间复杂度。
    每个询问$[L,R]$可以看作平面上的整点$(L,R)$,和另一个询问$(l,r)$之间的曼哈顿距离即为两个询问间转移的代价。
    我们要做的就是通过调整顺序,最小化询问间转移的代价之和。
    最优的计算顺序即为这些点的曼哈顿最小生成树,然而求解这东西非常麻烦,于是我们采取直接排序这一更为暴力的方法,获得时间复杂度和代码复杂度的平衡。


    什么时候用莫队算法

    当题目要求的操作较为复杂,限制性强,用线段树等数据结构不容易维护信息,或者维护信息复杂度较高,且题目对于时间的要求较为宽松时,支持离线,可以考虑使用莫队。
    时间复杂度一般带根号,带修改莫队复杂度更高,且常数大,如果可以直接线段树或者分块干掉的题目,尽量不要使用莫队,有些题跑的真的很慢(即使你算出的时间复杂度非常优秀)。

    适用条件:

      在序列上由$[L,R]$的答案伸缩左右端点时,仅为$Theta (1)$的复杂度。某些$Theta (log n)$转移答案的强行用莫队做,甚至不如$Theta O(n^2)$暴力跑得快。


    注意

      1.++和--是在前还是在后。

      2.一般情况下四种操作的顺序无所谓,但是有的题是有影响的,比方说:BZOJ4358:permu。


    代码时刻

    普通莫队:

    struct rec
    {
    	int id;
    	int l;
    	int r;
    	int pos;
    }q[N];
    int a[N];
    int ans[N];
    bool cmp(rec a,rec b){return a.pos==b.pos?a.r<b.r:a.pos<b.pos;}
    int main()
    {
    	int n,m;
    	scanf("%d%d",&n,&m);
    	int t=sqrt(n);
    	for(int i=1;i<=n;i++)
    		scanf("%d",&a[i]);
    	for(int i=1;i<=m;i++)
    	{
    		scanf("%d%d",&q[i].l,&q[i].r);
    		q[i].id=i;
    		q[i].pos=(q[i].l-1)/t+1;
    	}
    	sort(q+1,q+m+1,cmp);
    	int l=1,r=0;
    	for(int i=1;i<=m;i++)
    	{
    		while(l>q[i].l)upd(--l,1);
    		while(r<q[i].r)upd(++r,1);
    		while(l<q[i].l)upd(l++,0);
    		while(r>q[i].r)upd(r--,0);
    	}
    	for(int i=1;i<=m;i++)
    		printf("%d
    ",ans[i]);
    	return 0;
    }
    

    奇偶莫队:

    bool cmp(rec a,rec b){return (a.pos)^(b.pos)?a.l<b.l:(((a.pos)&1)?a.r<b.r:a.r>b.r);}
    

    rp++

  • 相关阅读:
    剑指OFFER 滑动窗口的最大值
    剑指OFFER 正则表达式匹配
    linux动态链接库的使用
    剑指OFFER 序列化二叉树
    剑指OFFER 数字在排序数组中出现的次数
    剑指OFFER 数组中的逆序对
    剑指OFFER 反转链表
    剑指OFFER 二叉树的深度
    剑指OFFER 矩形覆盖
    网络相关的命令工具-iptables
  • 原文地址:https://www.cnblogs.com/wzc521/p/11240671.html
Copyright © 2011-2022 走看看