1. 程式人生 > >P4137 Rmq Problem / mex

P4137 Rmq Problem / mex

單點 org sca n) oid 維護 using == show

題目地址:P4137 Rmq Problem / mex

用線段樹維護每一個數最後一次出現的位置(下標)和一個區間的數中每一個數最後一次出現的位置(下標)的最小值(即取min

對詢問按 \(r\) 排序,從左往右依次單點修改 \(a_i\) 位置的值

顯而易見的是,大於 \(n\) 的數可以直接扔掉

對於每一個詢問 \(l,r\) 查詢最小的最後一次出現的位置(下標)\(l\) 之前的數即可

如果強制在線可以用主席樹

代碼:

#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 6;
int n, m, a[N], ans[N];
struct Q {
    int l, r, d;
    inline bool operator < (const Q o) const {
        return r < o.r;
    }
} q[N];
struct T {
    int l, r, k;
} t[N<<2];

void build(int p, int l, int r) {
    t[p].l = l;
    t[p].r = r;
    if (l == r) return;
    int mid = (l + r) >> 1;
    build(p << 1, l, mid);
    build(p << 1 | 1, mid + 1, r);
}

void change(int p, int x, int k) {
    if (t[p].l == t[p].r) {
        t[p].k = k;
        return;
    }
    int mid = (t[p].l + t[p].r) >> 1;
    if (x <= mid) change(p << 1, x, k);
    else change(p << 1 | 1, x, k);
    t[p].k = min(t[p<<1].k, t[p<<1|1].k);
}

int ask(int p, int x) {
    if (t[p].l == t[p].r) return t[p].l;
    if (t[p<<1].k < x) return ask(p << 1, x);
    return ask(p << 1 | 1, x);
}

int main() {
    cin >> n >> m;
    build(1, 0, n);
    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].d = i;
    }
    sort(q + 1, q + m + 1);
    int r = 0;
    for (int i = 1; i <= m; i++) {
        while (r < q[i].r) {
            if (a[++r] > n) continue;
            change(1, a[r], r);
        }
        ans[q[i].d] = ask(1, q[i].l);
    }
    for (int i = 1; i <= m; i++) printf("%d\n", ans[i]);
    return 0;
}

P4137 Rmq Problem / mex