【luogu4137】 Rmq Problem / mex - 莫队

题目描述

有一个长度为n的数组{a1,a2,…,an}。m次询问,每次询问一个区间内最小没有出现过的自然数。

输入输出格式

输入格式:

第一行n,m。

第二行为n个数。

从第三行开始,每行一个询问l,r。

输出格式:

一行一个数,表示每个询问的答案。

思路

莫队算法详见『这里』

其实这题也不是莫队

a高达10^9,只能说是

数据水2333333333

#include <bits/stdc++.h>
using namespace std;
const int maxn = 200000 + 10;
int n,m,now,block,cnt[maxn],a[maxn],ans[maxn];
struct Query {
    int l,r,num;
    inline bool operator < (Query cmp) const {
        if (l/block != cmp.l/block) return l/block < cmp.l/block;
        return r < cmp.r;
    }
}q[maxn];
inline void add(int x) {
    if (x > n+1) return;
    cnt[x]++;
    if (now == x && cnt[x] > 0)
        for (int i = x;i <= n+1;i++)
            if (!cnt[i]) {
                now = i;
                break;
            }
}
inline void del(int x) {
    if (x > n+1) return;
    cnt[x]--;
    if (!cnt[x]) now = min(now,x);
}
int main() {
    scanf("%d%d",&n,&m);
    block = sqrt(n);
    a[0] = n+2;
    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].num = i;
    }
    sort(q+1,q+m+1);
    int l = 0,r = 0;
    for (int i = 1;i <= m;i++) {
        while (l < q[i].l) del(a[l++]);
        while (l > q[i].l) add(a[--l]);
        while (r < q[i].r) add(a[++r]);
        while (r > q[i].r) del(a[r--]);
        ans[q[i].num] = now;
    }
    for (int i = 1;i <= m;i++) printf("%d\n",ans[i]);
    return 0;
}

原文地址:https://www.cnblogs.com/lrj124/p/8641631.html

时间: 2024-12-13 20:35:37

【luogu4137】 Rmq Problem / mex - 莫队的相关文章

Luogu4137:Rmq Problem/mex

题面 传送门 Sol 这题可能是假的 离线莫队搞一搞,把数字再分块搞一搞,就行了 # include <bits/stdc++.h> # define IL inline # define RG register # define Fill(a, b) memset(a, b, sizeof(a)) using namespace std; typedef long long ll; const int _(2e5 + 5); IL ll Input(){ RG char c = getcha

BZOJ 3585 mex 莫队算法+分块

题目大意:给定一个长度为n的数组,m次询问某个区间内的mex值 怒写莫队233 将权值分成√n块,记录每个权值的出现次数以及每块内有多少权值出现过 修改O(1)即可完成 查询时首先扫一遍找到第一个块内有没有覆盖的点的块 然后在块内暴力查找 时间复杂度O(√n) 套个莫队 总时间复杂度O(m√n) #include <cmath> #include <cstdio> #include <cstring> #include <iostream> #include

Luogu P4137 Rmq Problem / mex

区间mex问题,可以使用经典的记录上一次位置之后再上主席树解决. 不过主席树好像不是很好写哈,那我们写莫队吧 考虑每一次维护什么东西,首先记一个答案,同时开一个数组记录一下每一个数出现的次数. 然后些比较显然的性质:如果加入一个数时,答案只会增加:同样的删除一个数时,答案只会减小 利用好这些性质我们就愉快地上莫队即可不过复杂度很迷,转移的时候只能近似\(O(1)\) CODE #include<cstdio> #include<cctype> #include<cmath&g

P4137 Rmq Problem / mex

思路 主席树维护mex 维护一下每个数上次出现的位置 [l,r]就是在r这颗线段树上查询位置小于l的最小的数 代码 #include <cstdio> #include <algorithm> #include <cstring> using namespace std; struct Node{ int lson,rson,minx; }Seg[200200*30]; int n,m,root[200200],Nodecnt,a[200200]; void pushu

【题解】P4137 Rmq Problem(莫队)

[题解]P4137 Rmq Problem(莫队) 其实这道题根本就不用离散化! 因为显然有\(mex\)值是\(\le 2\times 10^5\)的,所以对于大于\(2\times 10^5\)的数我们可以忽略. 然后直接莫队算就是的,开一个\(2e5\)的桶 若一个比答案小的值的桶为\(0\)了:答案更新为它 若这个\(mex\)的桶突然有值了:暴力枚举答案变大,第一个桶里没值的就是答案,更新. 有小伙伴会问,这复杂度不上天了?其实不然.移动\(ans\)的总复杂度(好像)是\(O(n\s

bzoj3339 rmq problem (range mex query)

给一个长度为n的数列a,q个询问,每次询问一段区间的mex.(没有出现过的最小非负整数) 1<=n,q<=200000,0<=ai<=200000. 题解1 莫队 我们将权值分成根号块,记录每个权值的出现次数和每块内有多少权值出现过. 修改和询问就直接暴力做就行. 修改O(1),询问O(sqrt(n)),加在一起还是O((n+q)sqrt(n+q)). #include <iostream> #include <stdio.h> #include <s

【BZOJ】3339: Rmq Problem &amp; 3585: mex(线段树+特殊的技巧)

http://www.lydsy.com/JudgeOnline/problem.php?id=3585 好神的题. 但是!!!!!!!!!!!!!!我线段树现在要开8倍空间才能过!!!!!!!!!!这什么梗...................... 我思考了很久空间的问题,因为我在pushdown的时候可能会越界,或许是pushup? 不管了.然后看了zyf的写法.看来以后得注意下...pushdown弄成先放了... 本题的做法: 好神orz 首先像莫队一样离线区间,左端点在前. 考虑如何

[BZOJ 3585] mex 【莫队+分块】

题目链接:BZOJ - 3585 题目分析 区间mex,即区间中没有出现的最小自然数. 那么我们使用一种莫队+分块的做法,使用莫队维护当前区间的每个数字的出现次数. 然后求mex用分块,将权值分块(显然mex 一定小于等于 n ,大于 n 的权值没有意义,可以直接忽略),每块大小 sqrt(n) . 然后区间中的某个数的数量被减到0的时候就将它所在的块的种类计数减一,添加数的时候类似. 然后枚举每个块,找到最小的中间有数不存在的块(即种类数小于块中的数的种数),然后到这个快里直接从小一个一个找到

BZOJ3339:Rmq Problem &amp; BZOJ3585 &amp; 洛谷4137:mex——题解

前者:https://www.lydsy.com/JudgeOnline/problem.php?id=3339 后者: https://www.lydsy.com/JudgeOnline/problem.php?id=3585 https://www.luogu.org/problemnew/show/P4137 有一个长度为n的数组{a1,a2,…,an}.m次询问,每次询问一个区间内最小没有出现过的自然数. 题解大部分都是莫队分块,但是复杂度为O(n*sqrt(n))=5e2*2e5=1e