• 主席树


    主席树

    例题链接

    学主席树静态求区间第k大之前,应先学会普通线段树如何求整个序列第k大

    建一棵值域线段树,每位的值为当前值有多少个。 然后类似平衡树一样求第k大

    主席树是一颗可持久化线段树。 我们发现每次更新一个点的值, 只会改变那个点到根上路径的所有点, 那我们可以动态开点, 重新连一条链出来。

    然后利用前缀和的思想, [1~r]的线段树 对应点权值 减去 [1~l-1] 上的权值
    就可以得到[l~r]这段区间的信息

    然后就可以求区间第k大了

    Code

    #include<bits/stdc++.h>
    
    using namespace std;
    
    inline int gi() {
        int f = 1, s = 0;
        char c = getchar();
        while (c != '-' && (c < '0' || c > '9')) c = getchar();
        if (c == '-') f = -1, c = getchar();
        while (c >= '0' && c <= '9') s = s*10+c-'0', c = getchar();
        return f == 1 ? s : -s;
    }
    
    const int N = 200010;
    
    struct node {
        int v, id;
        bool operator < (node z) const{
            return v < z.v;
        }
    }a[N];
    
    int b[N], cnt;
    
    struct tree {
        int lc, rc, v;
    }t[N*20];
    int root[N], ans[N];
    
    void update(int l, int r, int pos, int &now) {
        t[++cnt] = t[now];
        now = cnt;//这里的now带的是指针, 往下更新时要把它指向更新的儿子
        t[now].v++;
        if (l == r) return ;
        int mid = (l + r) >> 1;
        if (pos <= mid)
            update(l, mid, pos, t[now].lc);
        else update(mid+1, r, pos, t[now].rc);
        return ;
    }
    
    int query(int l, int r, int rt1, int rt2, int k) {
        if (l == r) return l;
        int s = t[t[rt2].lc].v - t[t[rt1].lc].v, mid = (l + r) >> 1;
        if (s >= k)
            return query(l, mid, t[rt1].lc, t[rt2].lc, k);
        else return query(mid+1, r, t[rt1].rc, t[rt2].rc, k - s);
    }
    
    int main() {
        int n = gi(), m = gi();
        for (int i = 1; i <= n; i++) {
            a[i].v = gi(); a[i].id = i;
        }
        sort(a+1, a+1+n);
        int v = 1;
        b[a[1].id] = v; ans[v] = a[1].v;
        for (int i = 2; i <= n; i++) {
            if (a[i].v != a[i-1].v) v++;
            b[a[i].id] = v; ans[v] = a[i].v;
        }
        for (int i = 1; i <= n; i++) {
            root[i] = root[i-1];
            update(1, n, b[i], root[i]);
        }
        while (m--) {
            int l = gi(), r = gi(), k = gi();
            printf("%d
    ", ans[query(1, n, root[l-1], root[r], k)]);
        }
        return 0;
    }
    
    
  • 相关阅读:
    47种常见的浏览器兼容性问题大汇总
    201521123029《java程序设计》第2周学习总结
    201521123029《Java程序设计》第1周学习总结
    201521123022 《Java程序设计》 第一周学习总结
    201521123020《java程序设计》第1周学习总结
    Java程序设计第三周学习总结
    201521123021第二周Java学习总结
    201521123021《Java程序设计》第1周学习总结
    201521123017 《Java程序设计》第1周学习总结
    201521123028 《Java程序设计》第2周学习总结
  • 原文地址:https://www.cnblogs.com/zzy2005/p/10135076.html
Copyright © 2020-2023  润新知