zoukankan      html  css  js  c++  java
  • 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
    ", query(root[y], 1, tot, x));
        }
        return 0;
    } 
    View Code
  • 相关阅读:
    龙东平:持续提升个人认知的三大底层逻辑
    【科创人独家】美信拓扑创始人一乐:如何登山不是最重要的问题,山峰才是
    【科创人独家】搜狐快站金庸:有情有义,90后技术创业者的问剑之路
    【科创人独家】军哥手记程军:我的2020,先打个60分吧
    【科创人独家】云风:从创业到招安,自由的游戏玩家+务实的程序员
    C语言--->指针
    位运算(一)
    平方根倒数快速算法
    IntelliJ IDEA 配置《算法》(第四版)
    深度学习(一):Python神经网络——手写数字识别
  • 原文地址:https://www.cnblogs.com/CzxingcHen/p/9519853.html
Copyright © 2011-2022 走看看