zoukankan      html  css  js  c++  java
  • 主席树算法解析

    主席树

    感想:

    这个主席树我还是学了接近一周了,虽然思想懂得比较快,但是一直比较浮躁,所以

    一直都没有静下来去看代码,但是在一周的慢慢消化中,我还是懂了主席树的思想和代码

    ,我也看了其他大牛的博客,都写的很好,所以我的这一篇都是比较水的

     

    主席树是线段树的一种分支,可以解决一道题中的历史遗留问题或者第几大

    例如:12532234

    求区间 37】中的第三小的数字,我们可以很容易的看出是3

    然后这样一种类型其实就是主席树的模板题了

    推荐模板题:poj2104  

    Poj2761

    Hdu2665

     

    算法:我的语言形容能力不好,我就尽量用图来表达吧

    定义的量:

    T[],sum[],R[],L[],a[],b[],d,tot,rt

    T[]:第几棵树的含有的数字个数

    Sum[i]:节点i含有的数字个数

    L[i]:节点i的左边界

    R[i]:节点i的右边界

    d:去重后数组剩下的个数

    Tot:最后的节点总数

    1.首先我们建立一棵空树,里面每一个节点都是0

     

    2.然后向里面加点,我们先挨着建树,没有优化,每一个节点存的是区间里的数字个数

    3.用一个优化的图,这种方式不会爆内存(因为画完的话占的面积太大,所以我就举例子加入第8个点时,即树7向树8转换)

    树8就是除去蓝色斜杠杠掉的节点

     

    4.假如我们要求区间[3,7]3小,我们就用树7去减树2再来看(l,r区间求法是:t[r]-t[l-1]

     

    5.接着在这棵树上不断判断midk的关系,找到第k

     

    这就是这个主席树了,我们接着来看代码

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<iostream>
     4 #include<algorithm>
     5 #include<cstdlib>
     6 #include<cmath>
     7 #define maxn 100005
     8 using namespace std;
     9 
    10 int sum[maxn<<5],L[maxn<<5],R[maxn<<5],t[maxn<<5];
    11 int tot,d,x,m,n,a[maxn],b[maxn];
    12 
    13 int build(int l,int r)//在这个问题里,这一步实际意义不大,就是建立空树 
    14 {//                      主要是累加tot 
    15     int rt=(++tot);
    16     int m=(l+r)>>1;
    17     sum[rt]=0;
    18     if(l<r)
    19     {
    20         build(l,m);
    21         build(m+1,r);
    22     }
    23     return rt;
    24 }
    25 
    26 int update(int pre,int l,int r,int x)
    27 {
    28     int rt=(++tot);
    29     L[rt]=L[pre];R[rt]=R[pre];sum[rt]=sum[pre]+1;
    30     if(l<r)
    31     {
    32         int m=(l+r)>>1;
    33         if(x<=m)L[rt]=update(L[pre],l,m,x);//需要变更的链 
    34         else R[rt]=update(R[pre],m+1,r,x);
    35     }
    36     return rt;
    37 }
    38 
    39 int query(int u,int v,int l,int r,int k)
    40 {
    41     if(l>=r)return l;
    42     int m=(l+r)>>1;
    43     int num=sum[L[v]]-sum[L[u]];//两棵树对应节点相减 
    44     if(num>=k){//左边已经到了第num名 
    45         return query(L[u],L[v],l,m,k);
    46     }else return query(R[u],R[v],m+1,r,k-num);
    47     
    48 }
    49 
    50 int main()
    51 {
    52     scanf("%d%d",&n,&m);
    53     for(int i=1;i<=n;i++) 
    54     {
    55         scanf("%d",&a[i]);
    56         b[i]=a[i];    
    57     }
    58     sort(b+1,b+n+1); 
    59     int d=unique(b+1,b+n+1)-(b+1);//去重后的数字个数
    60     t[0]=build(1,d);
    61     for(int i=1;i<=n;i++)
    62     {
    63         int x=lower_bound(b+1,b+d+1,a[i])-b;
    64         t[i]=update(t[i-1],1,d,x); 
    65     }
    66     for(int j=1;j<=m;j++)
    67     {
    68         int l,r,k;
    69         scanf("%d%d%d",&l,&r,&k);
    70         int y=query(t[l-1],t[r],1,d,k);//求l,r区间就是树r减去l-1 
    71         printf("%d
    ",b[y]);
    72     }
    73     
    74 } 

     

    PS:第一次发这么长的帖子,可能会有很多瑕疵,希望诸位大佬指出

     

  • 相关阅读:
    试题 历届试题 整数拼接(数位dp)
    试题 历届试题 波动数列(dp)
    序列化二叉树(模拟)
    对于maven中无法加载类路径下的配置文件
    [蓝桥杯][算法训练]文章翻转
    [蓝桥杯][算法训练] 无权最长链
    [蓝桥杯][基础训练]2n皇后问题
    蓝桥杯 基础练习——Huffuman树
    蓝桥杯 基础练习——高精度加法
    蓝桥杯 基础练习——阶乘计算
  • 原文地址:https://www.cnblogs.com/Danzel-Aria233/p/7238497.html
Copyright © 2011-2022 走看看