P4137 Rmq Problem / mex

链接

https://www.luogu.org/problemnew/show/P4137

思路

做了好几次,每次都得想一会,再记录一下
可持久化权值线段树
区间出现存最小的下标
然后线段树上二分
如果左边min>L
那就去右边
因为左边都被【L,R】占满了
虽然比卡常的莫队慢好多(700ms和1000ms)
但是理论上快哇

线段树

// luogu-judger-enable-o2
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 7;
const int inf = 0x3f3f3f3f;
inline int read() {
    int x = 0, f = 1; char s = getchar();
    for(; s > '9' || s < '0'; s = getchar()) if(s == '-') f = -1;
    for(; s >= '0' && s <= '9'; s = getchar()) x = x * 10 + s - '0';
    return x * f;
}
int n, m, a[N], rt[N];
namespace seg_tree {
    #define ls e[rt].ch[0]
    #define rs e[rt].ch[1]
    struct node {int ch[2],mex;}e[N*31];
    int cnt;
    void modify(int &rt, int old, int l, int r, int L) {
        rt = ++cnt;
        e[rt] = e[old];
        if(l == r) {
            e[rt].mex = L; 
            return;
        }
        int mid = (l + r) >> 1;
        if(a[L] <= mid) modify(ls, e[old].ch[0], l, mid, L);
        else modify(rs, e[old].ch[1], mid + 1, r, L);
        e[rt].mex = min(e[ls].mex ,e[rs].mex);
    }
    int query(int rt, int l, int r, int L) {
        if(l == r) return l;
        int mid = (l + r) >> 1;
        if(e[ls].mex >= L) return query(rs, mid + 1, r, L);
        else return query(ls, l, mid, L);
    }
}
int main() {    
    n = read(), m = read();
    for (int i = 1; i <= n; ++i) a[i] = min(read(), 200000);
    for (int i = 1; i <= n; ++i) {
        seg_tree::modify(rt[i], rt[i-1], 0, 200000, i);
    }
    for (int i = 1; i <= m; ++i) {
        int x = read(), y = read();
        printf("%d\n", seg_tree::query(rt[y], 0, 200000, x));
    }
    return 0;
}

莫队

// luogu-judger-enable-o2
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <cstdio>
#define maxn 301001
using namespace std;
int n,m,now;
int a[maxn];
int belong[maxn];
int vis[maxn];
int ma;
struct node {
    int l,r,id;
} q[maxn];
int ans[maxn];
inline int read() {
    int x=0,f=1;char s=getchar();
    while('0'>s||s>'9') {if(s=='-') f=-1;s=getchar();}
    while('0'<=s&&s<='9') {x=x*10+s-'0';s=getchar();}
    return x*f;
}
inline bool cmp(node a,node b) {
    return belong[a.l]==belong[b.l] ? belong[a.l]&1 ? a.r<b.r : a.r>b.r : belong[a.l]<belong[b.l];
}
inline void add(int x) {
    ++vis[x];
    if(now < x) return;
    if(now==x&&vis[x]==1) {
        for(int i=now+1; i<n; ++i) {
            if(!vis[i]) {
                now=i;
                return;
            }
        }
    }
}
inline void delet(int x) {
    --vis[x];
    if(now < x) return;
    if(now > x) {
        if(!vis[x]) {
            now=x;
        }
    }
}
int main() {
    
    n=read();
    m=read();
    int k=n/sqrt(m);
    for(int i=1; i<=n; ++i) {
        a[i]=read();
        if(a[i] > n)
            a[i]=n+1;
    }   
    for(int i=1; i<=n; ++i)
        belong[i]=(i-1)/k+1;
    for(int i=1; i<=m; ++i)
    {
        q[i].l=read();
        q[i].r=read();
        q[i].id=i;  
    }
    sort(q+1,q+1+m,cmp);
    int l=1,r=0;
    for(int i=1; i<=m; ++i) {
        while(l > q[i].l) add(a[--l]);
        while(l < q[i].l) delet(a[l++]);
        while(r < q[i].r) add(a[++r]);
        while(r > q[i].r) delet(a[r--]);
        ans[q[i].id]=now;
    }
    for(int i=1; i<=m; ++i)
        printf("%d\n",ans[i]);
    return 0;
}
全部评论

相关推荐

10-15 15:00
潍坊学院 golang
跨考小白:这又不是官方
投递拼多多集团-PDD等公司10个岗位
点赞 评论 收藏
分享
11-18 09:44
Java
小白也想要offer:简历别放洋屁,搞不还还放错了,当然你投外企除外,以上纯属个人观点
点赞 评论 收藏
分享
评论
点赞
收藏
分享
牛客网
牛客企业服务