[知识点]莫队大法好

昨天的模拟赛T3是个非常恶心的东东,不过今天获知有人莫队+O3卡常A了==

但是原来OD表示莫队目前没什么用不用学,就没学过,所以昨天无奈不会打

但是今天哼哼,学会了这个新的知识点,而且觉得还是挺好用的啊

毕竟暴力是哪里都能用得上的。。。



所谓莫队,是一个优雅的暴力

解决的问题就是离线区间询问,好像是无敌的。(然而区间修改我目前还不会,而且区间最值好像也不会,而且区间最值也不用莫队233)

首先我们知道区间[L,R],那么我们一定能暴力求出来[L‘,R‘]。我们将所有询问存起来,暴力求出来第一个区间,然后用这个区间去更新下一个区间(其实就是相当于不用算两区间重合的部分了)

为了我们暴力求的不重合的区间尽量少,我们会选择排序。那么如何排序呢?肯定不能严格按第一关键左端点升序,第二关键右端点升序来搞。对于随机数据这样还好,但是对于出题人存心卡你的数据效率就又降下来了。比如区间[1,100]推区间[2,3],肯定会很慢。

所以为了解决这个问题,我们需要让左端点“大概”呈上升趋势,然后搞右端点(就是让两个区间之间离得近)。于是出现了最小曼哈顿距离生成树(然而我们并不用它233)

有一个优美的方法那就是另一个暴力——分块大法!

当然我们这里只需要分块中的块就好啦,我们把所有询问区间以左端点的块升序排序,如果相同就以右端点(它本身)排序,这样就能提高效率

时间复杂度大概是O(n*√n)  (拒绝证明因为不会)

然后我们只需要循环一遍,用上一个区间求这个区间(暴力更新不重合部分即可),然后储存答案最后输出即可。



上例题:[SDOI2009]HH的项链 比较裸的莫队了

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
#define pos(i,a,b) for(int i=(a);i<=(b);i++)
#define N 210000
#define LL long long
int a[N];
int n,m,k;
int match[N],len,cnt[1001000];
LL ans[N];
struct haha{
    int l,r,id;
}edge[N];
bool cmp(const haha &a,const haha &b){
    if(match[a.l]==match[b.l]) return a.r<b.r;
    return match[a.l]<match[b.l];
}
void add(int i,int num){
    if(cnt[num]==0) ans[i]++;
    cnt[num]++;
}
void erase(int i,int num){
    cnt[num]--;
    if(cnt[num]==0) ans[i]--;
}
int main(){
    scanf("%d",&n);
    len=(int)sqrt(n+0.5);
    //cout<<len<<endl;
    pos(i,1,n) scanf("%d",&a[i]),k=max(a[i],k);
    pos(i,1,n){
        match[i]=(i-1)/(len+1);
    }
    scanf("%d",&m);
    pos(i,1,m){
        scanf("%d%d",&edge[i].l,&edge[i].r);
        edge[i].id=i;
    }
    sort(edge+1,edge+m+1,cmp);
    int lastl,lastr;
    lastl=edge[1].l;lastr=edge[1].r;
    pos(i,lastl,lastr){
        cnt[a[i]]++;
    }

    pos(i,0,k){
        if(cnt[i]!=0)  ans[edge[1].id]++;
    }

    pos(i,2,m){
        ans[edge[i].id]=ans[edge[i-1].id];
        int nowl=edge[i].l,nowr=edge[i].r;
        if(nowl>=lastl) pos(j,lastl,nowl-1)  erase(edge[i].id,a[j]);
        else  pos(j,nowl,lastl-1)  add(edge[i].id,a[j]);

        if(nowr>=lastr)  pos(j,lastr+1,nowr)  add(edge[i].id,a[j]);
        else  pos(j,nowr+1,lastr) erase(edge[i].id,a[j]);

        lastr=nowr;lastl=nowl;

    }
    pos(i,1,m) printf("%lld\n",ans[i]);
    return 0;
}

  



好啦新技能 莫队 get√

时间: 2024-10-30 01:59:26

[知识点]莫队大法好的相关文章

BZOJ 2038 小z的袜子 &amp; 莫队算法(不就是个暴力么..)

题意: 给一段序列,询问一个区间,求出区间中.....woc! 贴原题! 作为一个生活散漫的人,小Z每天早上都要耗费很久从一堆五颜六色的袜子中找出一双来穿.终于有一天,小Z再也无法忍受这恼人的找袜子过程,于是他决定听天由命…… 具体来说,小Z把这N只袜子从1到N编号,然后从编号L到R(L 尽管小Z并不在意两只袜子是不是完整的一双,甚至不在意两只袜子是否一左一右,他却很在意袜子的颜色,毕竟穿两只不同色的袜子会很尴尬. 你的任务便是告诉小Z,他有多大的概率抽到两只颜色相同的袜子.当然,小Z希望这个概

【字符串哈希】【莫队算法】bzoj3207 花神的嘲讽计划Ⅰ

既然询问的长度是确定的,那么我们可以将所有长度为K的字串弄个哈希值出来,这样字串存在性=>哈希值存在性. 自然上溢哈希,base=107比较不错. 序列长度n=>n-K+1 询问区间[x,y]=>[x,y-K+1] 注意特判x是否>y-K+1 然后我们注意到没有修改,于是将哈希值离散化后,莫队大法好. #include<cstdio> #include<cmath> #include<algorithm> using namespace std;

csu1515 squence 莫队算法

莫队大法好,分块一同乱搞. 远哥出的题,当时没做出来,今天才学会莫队. 如果[l,r] -> [l,r+1] 可以在o(1)时间内求出,就可以sqrt(n)分块后,对询问排序更新. 因为我写的太丑了,必须用输入外挂才过了. 复杂度msqrt(n) 代码: #include<iostream> #include<cstdio> #include<cmath> #include<algorithm> #include<cstring> #inc

LightOJ 1188 Fast Queries(简单莫队)

1188 - Fast Queries    PDF (English) Statistics Forum Time Limit: 3 second(s) Memory Limit: 64 MB Given an array of N integers indexed from 1 to N, and q queries, each in the form i j, you have to find the number of distinct integers from index i to 

莫队算法~讲解

用了大约1h搞定了基础的莫队算法.写篇博客算是检验下自己的学习成果. 一.什么是莫队算法? 莫队算法是用来处理一类无修改的离线区间询问问题.——(摘自前国家队队长莫涛在知乎上对莫队算法的解释.) 莫队算法是前国家队队长莫涛在比赛的时候想出来的算法. 传说中能解决一切区间处理问题的莫队算法. 准确的说,是离线区间问题.但是现在的莫队被拓展到了有树上莫队,带修莫队(即带修改的莫队).这里只先讲普通的莫队. 还有一点,重要的事情说三遍!莫队不是提莫队长!莫队不是提莫队长!!莫队不是提莫队长!!! 二.

洛谷 P3674 小清新人渣的本愿 [莫队 bitset]

传送门 题意: 给你一个序列a,长度为n,有Q次操作,每次询问一个区间是否可以选出两个数它们的差为x,或者询问一个区间是否可以选出两个数它们的和为x,或者询问一个区间是否可以选出两个数它们的乘积为x ,这三个操作分别为操作1,2,3 题面太强啦!!! 感觉就是莫队,想了一下分块不好搞更坚定了莫队的信念 $a-b=x$,$a=x+b$,放在权值数组上就是b右移x位,$bitset$大法好 加法同理 乘法,总共就$\sqrt{N}$个约数.... #include <iostream> #incl

【BZOJ 3735】苹果树 树上莫队(树分块+离线莫队+鬼畜的压行)

学习了树上莫队,树分块后对讯问的$dfs序$排序,然后就可以滑动树链处理答案了. 关于树链的滑动,只需要特殊处理一下$LCA$就行了. 在这里一条树链保留下来给后面的链来转移的$now$的为这条树链上所有点除去$LCA$的颜色种数.因为如果要考虑$LCA$情况就太多了,不如单独考虑$LCA$. 转移后加上当前链的$LCA$进行统计,然后再去掉这个$LCA$更新一下$now$值给后面的链转移. 这都是我的理解,说的有点不清楚,具体请看vfk的题解 OTZ 虽然不是这道题,但是通过这篇博客学习树上莫

(莫队算法)CodeForces - 617E XOR and Favorite Number

题意: 长度为n的数列,m次询问,还有一个k.每次询问询问询问从数列的L到R内有多少个连续子序列异或起来等于k. 分析: 因为事先知道这题可以用莫队写,就正好用这题练习莫队. 预处理每个前缀异或和. 然后莫队按分块排序后,不断更新,用一个数组cnt[]记录当前L到R前缀和的数量. R向右拉,新增的数量就是cnt[pre^k],pre表示当前这个R位置的前缀异或和,然后更新一下cnt. 其他的也类似. 算是一个比较好的入门题. 代码: 1 #include <cstdio> 2 #include

莫队算法

Beautiful Girl 题意 给定一个长度为 n 的序列 a[1], a[2], ..., a[n] . m 组询问 (l, r, K) , 求区间 [l, r] 去除重复的数之后的第 K 小. n, m <= 100000 . 分析 莫队算法 + 值域分块. 1 #include <cstdio> 2 #include <cstring> 3 #include <cstdlib> 4 #include <cctype> 5 #include &