zoukankan      html  css  js  c++  java
  • 主席树

    主席树是啥??

    主席树其实就是可持久化线段树。。。

    原来听这个名字一直觉得很厉害,但是后来知道它就是可持久化线段树之后。。。

    其实根本不用看网上博客口胡就能写出来了。

    可持久化数据结构

    可持久化数据结构就是在原来的数据结构基础上增加访问历史版本的功能。

    如果不可持久化怎考虑这个问题?

    有一种直接的方法是每次操作线段树都重新开一个线段树。

    这样的空间复杂度很巨大的。

     如何用有一个空间复杂度和时间复杂度更加优秀的数据结构呢?

    我们发现每次修改线段树,有很多节点是没有变化的。也就是说,我们只需要对其中一部分节点进行修改就可以了。

    我们另外开一个数组记录每次操作过后的根节点序号。

    每次修改一个点,不直接修改那个点,而是新建一个和之前一模一样的点,之后的所有操作都在这个点上进行就可以了。

    模板题

    主席树

    现在我们已经学会对线段树可持久化了,怎么解决这道题呢。

    然后你会发现学习怎么可持久化并不难,难的在怎么运用。

    在这道题中我们需要维护一个区间k大。

    可以考虑把线段树的维护的范围转化为数组的值域,维护的点转化为每个元素的个数,操作的版本转化为加入第i个元素之后的元素个数。

    这样子我们就可以求出每段区间里面每个元素的个数了。

    然后我们就可以找出某个区间k大了。

    代码

     1 #include <bits/stdc++.h>
     2 #define Mid ((l+r)>>1)
     3 #define lson(x) tree[x].ls
     4 #define rson(x) tree[x].rs
     5 #define Val(x) tree[x].val
     6 using namespace std;
     7 const int N=2e6+109;
     8 int read(){
     9     char c;int num,f=1;
    10     while(c=getchar(),!isdigit(c))if(c=='-')f=-1;num=c-'0';
    11     while(c=getchar(), isdigit(c))num=num*10+c-'0';
    12     return f*num;
    13 }
    14 struct Node{
    15     int ls,rs,val;
    16 }tree[N*5];
    17 int hver[N];
    18 int rn,n,m,ct=0;
    19 int a[N],ra[N],tot=0;
    20 void update(int x){
    21     Val(x)=Val(lson(x))+Val(rson(x));
    22 }
    23 int New(int l,int r,int v){
    24     tree[++tot]=(Node){l,r,v};
    25     return tot;
    26 }
    27 int Cpy(int v){
    28     tree[++tot]=tree[v];
    29     return tot;
    30 }
    31 int fd(int x){
    32     int l=0,r=rn;
    33     while(l<=r){
    34         if(ra[Mid]==x)return Mid;
    35         if(ra[Mid]<=x)l=Mid+1;
    36         else r=Mid-1;
    37     }
    38     return -1;
    39 }
    40 int build(int l,int r){
    41     if(l==r)return New(0,0,0);
    42     //如果是一个区间,新建点 
    43     return New(build(l,Mid),build(Mid+1,r),0);
    44     //建左树,建右树,建当前点 
    45 }
    46 int add(int l,int r,int x,int rt){
    47     if(l==r){
    48         int now=Cpy(rt);
    49         Val(now)++;
    50         return now;
    51     }
    52     int now=Cpy(rt);
    53     if(x<=Mid)lson(now)=add(l,Mid,x,lson(now));
    54     else rson(now)=add(Mid+1,r,x,rson(now));
    55     Val(now)++;
    56     return now;
    57 }
    58 int query(int l,int r,int k,int a,int b){
    59     if(l==r){return l;}
    60     int lt=Val(lson(a))-Val(lson(b));
    61     //cout<<l<<" "<<r<<" "<<Val(a)<<" "<<Val(b)<<" "<<lt<<endl;
    62     //cout<<Val(lson(a))<<" "<<Val(lson(b))<<" "<<k<<endl; 
    63     if(k<=lt)
    64         return query(l,Mid,k,lson(a),lson(b));
    65     else return query(Mid+1,r,k-lt,rson(a),rson(b));
    66 }
    67 /*int que_num(int l,int r,int x,int rt){
    68     if(l==r)return Val(rt);
    69     if(x<=Mid)return que_num(l,Mid,x,lson(rt));
    70     else return que_num(Mid+1,r,x,rson(rt));
    71 }*/
    72 int main()
    73 {
    74     //freopen("data.in","r",stdin);
    75     n=read();m=read();
    76     for(int i=1;i<=n;i++)a[i]=ra[i]=read();
    77     sort(ra+1,ra+1+n);
    78     rn=unique(ra+1,ra+1+n)-ra-1;
    79     hver[0]=build(1,rn);
    80     //离散化以及建树 
    81     for(int i=1;i<=n;i++)
    82         hver[i]=add(1,rn,fd(a[i]),hver[i-1]);
    83     for(int i=1;i<=m;i++){
    84         int a,b,k;
    85         a=read();
    86         b=read();
    87         k=read();
    88         printf("%d
    ",ra[query(1,rn,k,hver[b],hver[a-1])]);
    89     }
    90     return 0;
    91 }
    View Code
  • 相关阅读:
    容器编排系统k8s之ReplicaSet和Deployment控制器
    容器编排系统k8s之Pod生命周期、健康/就绪状态探测以及资源限制
    容器编排系统k8s之资源标签、标签选择器、资源注解
    容器编排系统k8s之Pod资源配置清单基础
    容器编排系统k8s之Kubectl工具的基础使用
    容器编排系统k8s之基础入门
    抢先看:笔者亲历的2020年中国.NET开发者大会活动纪实
    谷歌的请求索引功能恢复了
    VuePress教程之深入理解插件API
    Linux将shell脚本配置成系统服务并设置开机自启
  • 原文地址:https://www.cnblogs.com/onglublog/p/10115145.html
Copyright © 2011-2022 走看看