Luogu 4137 Rmq Problem / mex

一个主席树题。

一开始想着直接动态开点硬搞就可以了,每次查询只要作一个类似于前缀和的东西看看区间有没有满,在主席树上二分就可以了。

但是这样是错的,因为一个权值会出现很多次……然后就错了。

所以我们考虑记录每一个权值最后出现的位置,直接开权值下标记录每一个权值最后出现的位置,因为是区间查询,所以可持久化一下,这样答案就是第一次出现位置小于$l$的最小权值,查询方法类似。

考虑到答案只可能是$a_{i} + 1, 0$,所以直接大力把$a_{i}, a_{i} + 1,0$都丢进去离散化。

注意线段树中权值0出现的位置不是inf,因为0也算自然数。

感觉离线下来也可以不用写可持久化。

自己一开始还是naive

Code:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

const int N = 4e5 + 5;
const int M = 5e6 + 5;
const int inf = 1 << 30;

int n, qn, tot = 0, a[N], b[N];

inline void read(int &X) {
    X = 0;
    char ch = 0;
    int op = 1;
    for(; ch > '9' || ch < '0'; ch = getchar())
        if(ch == '-') op = -1;
    for(; ch >= '0' && ch <= '9'; ch = getchar())
        X = (X << 3) + (X << 1) + ch - 48;
    X *= op;
}

inline int min(int x, int y) {
    return x > y ? y : x;
}

namespace PSegT {
    struct Node {
        int lc, rc, data;
    } s[M];
    
    int root[N], nodeCnt;
    
    #define mid ((l + r) >> 1)
    
    inline void up(int p) {
        if(p) s[p].data = min(s[s[p].lc].data, s[s[p].rc].data);
    }
    
    void ins(int &p, int l, int r, int x, int pre, int v) {
        p = ++nodeCnt;
        s[p].lc = s[pre].lc, s[p].rc = s[pre].rc;
        if(l == r) {
            s[p].data = v;
            return;
        }
        
        if(x <= mid) ins(s[p].lc, l, mid, x, s[pre].lc, v);
        else ins(s[p].rc, mid + 1, r, x, s[pre].rc, v);
        up(p);
    }
    
    int query(int p, int l, int r, int x) {
        if(!p || l == r) return b[l];
        
        if(s[s[p].lc].data < x) return query(s[p].lc, l, mid, x);
        else return query(s[p].rc, mid + 1, r, x); 
    }
    
} using namespace PSegT;

int main() {
    read(n), read(qn);
    b[++tot] = 0;
    for(int i = 1; i <= n; i++) {
        read(a[i]);
        b[++tot] = a[i], b[++tot] = a[i] + 1;
    }
    
    sort(b + 1, b + tot + 1);
    tot = unique(b + 1, b + 1 + tot) - b - 1;
    root[0] = nodeCnt = 0; //s[0].data = inf;
    for(int i = 1; i <= n; i++) {
        a[i] = lower_bound(b + 1, b + 1 + tot, a[i]) - b;
        ins(root[i], 1, tot, a[i], root[i - 1], i);
    }
    
    for(int x, y; qn--; ) {
        read(x), read(y);
        printf("%d\n", query(root[y], 1, tot, x));
    }
    return 0;
} 
View Code

 

posted @ 2018-08-22 19:21  CzxingcHen  阅读(143)  评论(0编辑  收藏  举报