• [Data]可持久化线段树-主席树


    可持久化线段树-主席树

    主席树又称函数式线段树,顾名思义,就是通过函数实现的,也称可持久化线段树,支持在线处理,可以访问历史版本,后一刻可参考前一刻的状态,充分利用共同数据,

    节省空间;主席树可以实现查询区间k小的问题等;

    主席树的每个节点对应一棵线段树,对于一个序列,我们采用前缀和的思想,如a[1],a[2],a[3],.....,每个前缀建一棵线段树,那么就共有N棵线段树,两棵线段树之差得到的就是

    某个区间数字出现的次数,插入一个值时,相当于新建一棵线段树,在前一棵线段树的基础上,新建logn个节点,其余的从前一棵线段树那里copy过来,线段树里维护的是在

    这n个数的序列中,排名第K的数出现的次数,若要处理区间[l,r]问题,只需要利用前缀和思想,rt[r]-rt[l-1]就好了,rt[l-1]处理的是区间1-(l-1),rt[r]处理的是区间1-r,所以rt[r]-rt[l-1]处理的

    就是区间l-r;

    更新

    首先需要建立一棵空线段树,rt数组里存的是第i棵线段树的根节点的编号,当我们插入一个值时,只需要修改从该节点到根的一条路径,若该节点进入线段树右子树,则左子树可以共用,若进入左子树,则右子树可以共用,直到到达叶子节点;

    查询 区间第k[L,R]

    思想为二分法,定义num=rt[now].val-rt[cmp].val,当k<=num时,直接往左子树查找,否则在右子树中查找,但注意num要减k,因为左子树肯定小于它了,直到L==R;

    luogu 3834:

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    #define maxn 200009
    int cnt=0,a[maxn],s[maxn],ls[maxn*20],rs[maxn*20],val[maxn*20],rt[maxn],sz;
    void build(int &p,int l,int r){
        p=++cnt;
        if(l!=r){
            int mid=(l+r)/2;
            build(ls[p],l,mid);
            build(rs[p],mid+1,r);
        }
    }
    void insert(int &p,int cmp,int x,int l,int r){
        p=++cnt;ls[p]=ls[cmp];rs[p]=rs[cmp];val[p]=val[cmp]+1;
        if(l!=r){
            int mid=(l+r)/2;
            if(x<=mid){
                insert(ls[p],ls[cmp],x,l,mid);
            }
            else{
                insert(rs[p],rs[cmp],x,mid+1,r);
            }
        }
    }
    int query(int l,int r,int L,int R,int k){
        if(L==R) return L;
        int num=val[ls[r]]-val[ls[l]],mid=(L+R)/2;
        if(k<=num) return query(ls[l],ls[r],L,mid,k);
        else return query(rs[l],rs[r],mid+1,R,k-num); 
    }
    int main()
    {
        int n,m,l,r,k,i;
        scanf("%d%d",&n,&m);
        for(i=1;i<=n;i++){
            scanf("%d",&a[i]);
            s[i]=a[i];
        }
        sort(s+1,s+n+1);
        sz=unique(s+1,s+n+1)-s-1;
        build(rt[0],1,sz);
        for(i=1;i<=n;i++){
            insert(rt[i],rt[i-1],lower_bound(s+1,s+sz+1,a[i])-s,1,sz);
        }
        for(i=1;i<=m;i++){
            scanf("%d%d%d",&l,&r,&k);
            printf("%d
    ",s[query(rt[l-1],rt[r],1,sz,k)]);
        }
    }
    主席树

     

  • 相关阅读:
    webstorm破解
    macos-WebStorm安裝
    CocoaPods安装与使用
    前端之HTML
    python调用百度语音(语音识别-斗地主语音记牌器)
    MySQL学习笔记(二)
    MySQL学习笔记(一)
    python网络编程
    计算机网络基础
    python之hashlib、configparser、logging模块
  • 原文地址:https://www.cnblogs.com/Fish-/p/8167829.html
Copyright © 2020-2023  润新知