zoukankan      html  css  js  c++  java
  • 【洛谷 P4137】 Rmq Problem / mex(主席树)

    题目链接
    容易发现,可能答案只有(0)、每个数,每个数(+1)
    于是把这(2n+1)个数建立一个权值线段树,可持久化一下,每个节点记录这个子树中最后加入数加入的时间的最小值(latest)(好好理解一下)。
    对于查询((l,r)),线段树上二分找到最小的(latest<l)的叶节点,那么答案就是这个节点代表的数。

    #include <cstdio>
    #include <cmath>
    #include <algorithm>
    #define INF 2147483647;
    using namespace std;
    inline int read(){
        int s = 0;
        char ch = getchar();
        while(ch < '0' || ch > '9') ch = getchar();
        while(ch >= '0' && ch <= '9'){ s = s * 10 + ch - '0'; ch = getchar(); }
        return s;
    }
    const int MAXN = 200010;
    const int MAXNLOGN = 10000010;
    struct SegTree{
        int lc, rc, latest;
    }t[MAXNLOGN];
    int cnt, root[MAXN], n, m, a, b;
    int val[MAXN], s[MAXN], num;
    inline void pushup(int x){
        t[x].latest = min(t[t[x].lc].latest, t[t[x].rc].latest);
    }
    int update(int x, int l, int r, int c, int d){
        int id = ++cnt; t[id] = t[x];
        if(l == r){ t[id].latest = d; return id; }
        else{
            int mid = (l + r) >> 1;
            if(c <= mid) t[id].lc = update(t[x].lc, l, mid, c, d);
            else t[id].rc = update(t[x].rc, mid + 1, r, c, d);
            pushup(id); return id;
        }
    }
    int query(int x, int l, int r, int c){
        if(l == r) return val[l];
        int mid = (l + r) >> 1;
        if(t[t[x].lc].latest < c) return query(t[x].lc, l, mid, c);
        else if(t[t[x].rc].latest < c) return query(t[x].rc, mid + 1, r, c);
        return val[num] + 1;
    }
    struct lsh{
        int val, id;
        int operator < (const lsh A) const{
            return val < A.val;
        }
    }p[MAXN];
    int build(int l, int r){
        int id = ++cnt;
        if(l == r) return id; 
        int mid = (l + r) >> 1;
        t[id].lc = build(l, mid);
        t[id].rc = build(mid + 1, r);
        pushup(id); return id;
    }
    int main(){
        n = read(); m = read();
        for(int i = 1; i <= n; ++i)
            p[i].val = read(), p[i].id = i;
        sort(p + 1, p + n + 2); 
        for(int i = 1; i <= n + 1; ++i){
            s[p[i].id] = (p[i].val == p[i - 1].val ? num : ++num);
            val[num] = p[i].val;
        }
        root[0] = build(1, num);
        for(int i = 1; i <= n; ++i)
            root[i] = update(root[i - 1], 1, num, s[i], i);
        for(int i = 1; i <= m; ++i){
            a = read(); b = read();
            printf("%d
    ", query(root[b], 1, num, a));
        }
        return 0;
    }
    
    
  • 相关阅读:
    拓扑排序
    Codeforces #503 C. Elections(贪心,逆向
    Codeforces #367 (Div. 2) D. Vasiliy's Multiset (trie 树)
    字典树
    最大子段和
    P1880 [NOI1995] 石子合并
    P1140 相似基因
    P1280 尼克的任务
    [BZOJ4064/Cerc2012]The Dragon and the knights
    [BZOJ4066]简单题
  • 原文地址:https://www.cnblogs.com/Qihoo360/p/11027940.html
Copyright © 2011-2022 走看看