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 pushup(int o){
    Seg[o].minx=min(Seg[Seg[o].lson].minx,Seg[Seg[o].rson].minx);
}
void modi(int l,int r,int &o,int last,int pos,int val){
    Seg[++Nodecnt]=Seg[last];
    o=Nodecnt;
    if(l==r){
        Seg[o].minx=val;
        return;
    }
    int mid=(l+r)>>1;
    if(pos<=mid)
        modi(l,mid,Seg[o].lson,Seg[last].lson,pos,val);
    else
        modi(mid+1,r,Seg[o].rson,Seg[last].rson,pos,val);
    pushup(o);
}
int query(int l,int r,int o,int x){
    if(Seg[o].minx>=x)
        return r+1;
    if(l==r)
        return l;
    int mid=(l+r)>>1;
    if(Seg[Seg[o].lson].minx<x)
        return query(l,mid,Seg[o].lson,x);
    else if(Seg[Seg[o].rson].minx<x)
        return query(mid+1,r,Seg[o].rson,x);
}
int main(){
    scanf("%d %d",&n,&m);
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        if(a[i]>n)
            a[i]=n+1;
        a[i]++;
        modi(1,n+2,root[i],root[i-1],a[i],i);
    }
    for(int i=1;i<=m;i++){
        int l,r;
        scanf("%d %d",&l,&r);
        printf("%d\n",query(1,n+2,root[r],l)-1);
    }
    return 0;
} 

原文地址:https://www.cnblogs.com/dreagonm/p/10807451.html

时间: 2024-08-30 14:17:09

P4137 Rmq Problem / mex的相关文章

Luogu P4137 Rmq Problem / mex

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

【题解】P4137 Rmq Problem(莫队)

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

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

【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 +

Rmq Problem

大视野——3339: Rmq Problem Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 1192  Solved: 620[Submit][Status][Discuss] Description Input Output Sample Input 7 50 2 1 0 1 3 21 32 31 43 62 7 Sample Output 30324 HINT Source By Xhr 思路: 对于这个题似乎暴力不好打,而且似乎强制在线操作

【bzoj3339】Rmq Problem

[bzoj3339]Rmq Problem Description Input Output Sample Input 7 50 2 1 0 1 3 21 32 31 43 62 7 Sample Output 30324 HINT 分析 离线算法. 对于[l,r]区间的询问,我们可以线性求出来,然后考虑[l+1,r]区间有什么不同,在a[l]下一次出现的位置之前,所有大于a[l]的mex,都变成是a[l],因为 [l+1,a[l]下一次出现的位置-1],这个区间内没有a[l]了,大于它的数当然

【BZOJ】【3339】Rmq Problem

离线+线段树 Orz Hzwer,引用题解: 这一题在线似乎比较麻烦 至于离线.. 首先按照左端点将询问排序 然后一般可以这样考虑 首先如何得到1-i的sg值呢 这个可以一开始扫一遍完成 接着考虑l-r和l+1-r的答案有何不同 显然是l-next[l]-1这一段所有sg值大于a[l]的变为a[l] 这一步如果暴力修改的话只有30分 但是修改区间我们可以想到线段树,这样就能a了 晚上写题有点晕……忘了把当前时刻now置为q[i].l了,这种傻逼错误居然也犯…… 1 /**************

【BZOJ3489】A simple rmq problem kd-tree

[BZOJ3489]A simple rmq problem Description 因为是OJ上的题,就简单点好了.给出一个长度为n的序列,给出M个询问:在[l,r]之间找到一个在这个区间里只出现过一次的数,并且要求找的这个数尽可能大.如果找不到这样的数,则直接输出0.我会采取一些措施强制在线. Input 第一行为两个整数N,M.M是询问数,N是序列的长度(N<=100000,M<=200000) 第二行为N个整数,描述这个序列{ai},其中所有1<=ai<=N 再下面M行,每

bzoj 3339: Rmq Problem

3339: Rmq Problem Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 1270  Solved: 666[Submit][Status][Discuss] Description Input Output Sample Input 7 5 0 2 1 0 1 3 2 1 3 2 3 1 4 3 6 2 7 Sample Output 3 0 3 2 4 HINT Source By Xhr 嗯,莫队 懒得敲线段树,毕竟线段树比较短 #