zoukankan      html  css  js  c++  java
  • 洛谷 P3834 【【模板】可持久化线段树 1(主席树)】

    主席树模板题。
    首先我不认为这是什么很高级的数据结构,如果你已经对线段树掌握的很熟练的话应该不难理解主席树。

    正文部分:

    主席树一般用来解决静态区间的第(k)小问题。

    原理:

    首先我们可以在纸上画一张空的线段树。然后我们加入某个节点的时候你们就在纸上与这个节点所相关的节点的值就加(1)
    比如我们加入了值(1),那么受到影响的区间就有:([1,7],[1,4],[1,2],[1,1])
    好,当我们把所有的点都加完了之后,接下来就要解决第(k)小的问题。
    先假设我们查的区间为([l,r])那么我们就将第(l)颗线段树与第(r)颗线段树相减。其中所有节点所得的差就是某段区间里的值得个数。
    然后我们就可以查了。如果某段区间中的值得个数大于(k),我们就往左子树走,否则就减掉左子树,然后往右子树走。

    My Code:

    #include <bits/stdc++.h>
    #define il inline
    const int MAXN = 2e5 + 10;
    using namespace std;   
    int n,m,i,j,k,cnt;
    int a[MAXN],lsh[MAXN];
    int num[MAXN << 5],l[MAXN << 5],r[MAXN << 5],sum[MAXN << 5];
    template<typename T> il void read(T& res) {
        res = 0;char c;bool sign = 0;
        for(c = getchar();!isdigit(c);c = getchar()) sign |= c == '-';
        for(;isdigit(c);c = getchar()) res = (res << 1) + (res << 3) + (c ^ 48);
        (sign) && (res = -res);
        return;
    }
    int build(int l,int r) {
        cnt++;int num = cnt;
        if(l < r) {
            int mid = l + r >> 1;
            ::l[num] = build(l,mid);
            ::r[num] = build(mid + 1,r);
        }
        return num;
    }
    int modify(int pre,int l,int r,int mn) {
        cnt++;int num = cnt;
        ::l[num] = ::l[pre];::r[num] = ::r[pre];::sum[num] = ::sum[pre] + 1;
        if(l < r) {
            int mid = l + r >> 1;
            if(mn <= mid) ::l[num] = modify(::l[pre],l,mid,mn);
            else ::r[num] = modify(::r[pre],mid + 1,r,mn);
        }
        return num;
    }
    int query(int x,int y,int l,int r,int k) {
        if(l >= r) return l;
        int tmp = ::sum[::l[y]] - ::sum[::l[x]];
        int mid = l + r >> 1;
        if(tmp >= k) return query(::l[x],::l[y],l,mid,k);
        else return query(::r[x],::r[y],mid + 1,r,k - tmp);
    }
    int main() {
        read(n);read(m);
        for(int i = 1;i <= n;i++) {
            read(a[i]);lsh[i] = a[i];
        }	
        sort(lsh + 1,lsh + n + 1);int _n = unique(lsh + 1,lsh + n + 1) - lsh - 1;
        num[0] = build(1,_n);
        for(int i = 1;i <= n;i++) {
            int tmp = lower_bound(lsh + 1,lsh + _n + 1,a[i]) - lsh;
            num[i] = modify(num[i - 1],1,_n,tmp);
        }
    //	for(int i = 0;i <= n;i++) cout << num[i] << ' ';cout << endl;
        for(int i = 1;i <= m;i++) {
            int l,r,k;read(l);read(r);read(k);
            int tmp = query(num[l - 1],num[r],1,_n,k);        
            printf("%d
    ",lsh[tmp]);
        }
        return 0;
    }
    
  • 相关阅读:
    sql server报【将截断字符串或二进制数据】错误
    消息队列的一些知识
    excel中添加下拉候选
    君生我未生,我生君已老
    分库分表的几个面试题
    sql server判断表存在
    vue定义data的三种方式与区别
    sql server多表关联update
    使用CodeMirror在浏览器中实现编辑器的代码高亮效果
    Jquery easyui Tree的简单使用
  • 原文地址:https://www.cnblogs.com/Sai0511/p/10360356.html
Copyright © 2011-2022 走看看