• [知识学习] 莫队


    迟到的莫队知识总结

    最近学习了一种说优雅也挺优雅,说暴力也挺暴力的算法:莫队算法

    普通莫队

    例题

    给出一个长度为(n)的数列,(a_1,a_2,...,a_n),有(q)个询问,每个询问给出数对((i,j)),需要你给出(a_i,a_{i+1},...,a_j)这一段中有多少不同的数字

    当然你也可以做HH的项链,题意是一样的,只是这个题目卡了莫队算法

    • 首先考虑一下暴力

    对于每个询问,直接从(l)(r)扫一遍,统计 复杂度(O(nq)) 显然不行(废话

    • 考虑优化

    维护两个指针(l)(r),现在(l)(r)统计的区间就是([l,r]),每次往新的询问区间去靠近,分四种情况:

    1.([l,r]->[l+1,r]) :统计答案时先减去现在(l)位置的答案,再把(l++)

    2.([l,r]->[l,r+1]) :统计答案是先把(r++),在加上(r++)之后的位置的答案

    3.([l,r]->[l-1,r]) :统计答案是先把(l--),在加上(l--)之后的位置的答案

    4.([l,r]->[l,r-1]) :统计答案时先减去现在(r)位置的答案,再把(r--)

    总结一下规律:区间扩大时就先(l--)((r++)),再加上答案,区间缩小时就先减去答案,再(l++)((r--))

    这样就优化了不少,但对于询问区间一左一右来来回回跳动的情况,又退化成了(O(nq))

    • 进一步优化

    因为可以离线计算,所以可以先把询问区间存下来,排个序,按一定顺序进行询问,就可以避免出现一左一右询问的情况

    但是按什么来排序?每个区间的左端点顺序?

    显然不行吧,万一右端点又是一左一右的乱跳呢?

    这时,分块的思想就派上用场了;

    我们对询问进行分块,如果两个询问左端点在同一块,就按右端点的块排序,否则就按左端点的块排序

    这样就会每个块内指针跳动了,这也就是莫队算法的精髓

    贴个代码:

    #include <bits/stdc++.h>
    #define N (1000000+5)
    using namespace std;
    typedef long long LL;
    int n,m,l,r,bl;
    LL ans;
    int pos[N],cnt[N],a[N];
    LL res[N];
    struct node{
    	int l,r,id;
    }q[N];
    bool cmp(node x,node y){//对询问排序
    	if(pos[x.l]!=pos[y.l]) return pos[x.l]<pos[y.l];
    	return pos[x.r]<pos[y.r];
    }
    inline void add(int x){if(++cnt[x]==1) ans++;}//加答案
    inline void del(int x){if(--cnt[x]==0) ans--;}//减答案
    void solve(int l,int r){
    	sort(q+1,q+m+1,cmp);
    	for(int i=1;i<=m;i++){
    		node now=q[i];
    		while(l>now.l) add(a[--l]);//四个操作
    		while(r<now.r) add(a[++r]);
    		while(l<now.l) del(a[l++]);
    		while(r>now.r) del(a[r--]);
    		res[q[i].id]=ans;
    	}
    }
    int main(){
    	scanf("%d",&n);
    	bl=sqrt(n);
    	for(int i=1;i<=n;i++){
    		scanf("%d",&a[i]);
    	}
    	scanf("%d",&m);
    	for(int i=1;i<=m;i++){
    		scanf("%d%d",&q[i].l,&q[i].r);
    		q[i].id=i;
    		pos[i]=(i-1)/bl+1;//分块
    	}
    	solve(1,0);
    	for(int i=1;i<=m;i++){
    		printf("%lld
    ",res[i]);
    	}
    	return 0;
    }
    

    普通莫队是不是很简单?

    洛谷还有一道模板题:小Z的袜子

    只不过这个题要推柿子,就交给自己完成,这里就不展示代码了


    带修莫队

    先咕着,下午再更

    (咕咕咕)

    转载请注明出处--Xx_queue
  • 相关阅读:
    快速模幂
    UPC-2249 曲线分割【递推】
    maven 服务器
    maven repo
    php-fpm sock
    mysql
    go 1
    xdebug
    centos
    win10 2503 2502
  • 原文地址:https://www.cnblogs.com/Xx-queue/p/12205076.html
Copyright © 2020-2023  润新知