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

    主席树

    新学了个东西---主席树。。。又名可持久化线段树

    主席树最基础的应用就是 第K极值。(前提是静态,动态有动态的主席树

    首先第一大操作:建基树

    主席树是 1~n 每个节点都建一颗树,节点 rt 表示的是 1~rt 的什么什么值

    因为每个节点建的是值域线段树,所以要离散化(不然空间会爆)

    离散好后,先建个虚拟节点 0的以这个为基准的树(我这里简称基树)。

    建树过程和普通线段树差不多,分左右区间,只不过父节点与子节点的关系不再是 k<<1 和 k<<1|1,而是 dfs序。

    接着是第二大操作:建其他树

    1~n, 依次按原顺序加入节点。可因为每次操作最多只会涉及 logn 个节点,如果每个节点都建一颗线段树的话,空间可能承受不了。所以我们采用与前面树共用节点的方法。

    对于那些本次操作不涉及的节点,还是用原标号(具体操作是把根节点的边直接连向原节点),对于那些涉及的点,则只能另开新节点(注意涉及到的节点对应节点的什么什么值相比前面的要更新!!!)(具体操作见代码)

    第三大操作:查询第 k 极值

    这里分两种:

    1、1~i 的极值

    直接查询就可以了,和平衡树、二叉排序树一样的查法,分左右两个比大小。

    2、l~r 的极值

    就要用到前缀和的思想。设 x= sum[r]-sum[l],则如果 k<=x 则在树的左儿子,反之则在右儿子。(其实和上面差不多,只不过要用前缀和作差)(比较抽象,可能比较难理解,自己到网上找找博客,画画图,理解理解)。

    主席树的最基本操作基本就是这些(待填坑。。。)

    落谷模板题:AAAAAAAAAAAAAAAA

    贴代码:

     1 #include<bits/stdc++.h>
     2 #define mid (l+r)/2
     3 using namespace std;
     4 const int N=2e5+5;
     5 int n,q,m,cnt=0;
     6 int a[N],b[N],T[N];
     7 int sum[N<<5],L[N<<5],R[N<<5];
     8 
     9 inline int build(int l,int r)
    10 {
    11     int rt=++cnt;
    12     sum[rt]=0;
    13     if (l<r)
    14     {
    15         L[rt]=build(l,mid);
    16         R[rt]=build(mid+1,r);
    17     }
    18     return rt;
    19 }
    20 inline int update(int lst,int l,int r,int w)
    21 {
    22     int rt=++cnt;
    23     L[rt]=L[lst],R[rt]=R[lst]; sum[rt]=sum[lst]+1;
    24     if (l<r)
    25     {
    26         if (w<=mid) L[rt]=update(L[lst],l,mid,w);
    27         else R[rt]=update(R[lst],mid+1,r,w);
    28     }
    29     return rt;
    30 }
    31 inline int query(int u,int v,int l,int r,int k)
    32 {
    33     if (l>=r) return l;
    34     int x=sum[L[v]]-sum[L[u]];
    35     if (x>=k) return query(L[u],L[v],l,mid,k);
    36     else return query(R[u],R[v],mid+1,r,k-x);
    37 }
    38 int main()
    39 {
    40     scanf("%d%d",&n,&q);
    41     for (int i=1; i<=n; ++i)
    42     {
    43         scanf("%d",&a[i]);
    44         b[i]=a[i];
    45     }
    46     sort(b+1,b+1+n);
    47     m=unique(b+1,b+1+n)-b-1;
    48     T[0]=build(1,m);
    49     for (int i=1; i<=n; ++i)
    50     {
    51         int t=lower_bound(b+1,b+1+m,a[i])-b;
    52         T[i]=update(T[i-1],1,m,t);
    53     }
    54     while (q--)
    55     {
    56         int x,y,z;
    57         scanf("%d%d%d",&x,&y,&z);
    58         int t=query(T[x-1],T[y],1,m,z);
    59         printf("%d
    ",b[t]);
    60     }
    61     return 0;
    62 }
    View Code

    fighting fighting fighting !!!

  • 相关阅读:
    解决VS2012新建MVC4等项目时,收到加载程序集“NuGet.VisualStudio.Interop…”的错误
    BOM 清除
    sleep和Sleep区别
    出现error: stray ‘357’ in program的根源
    vi 复制或剪切多行超级强大方法
    CentOS乱码解决方法
    VBS实现文本文件按行数拆分的脚本
    python-门户应用状态检查脚本
    HTA+VBS实现的话单核查小工具
    oracle 11g 安装
  • 原文地址:https://www.cnblogs.com/Frank-King/p/9858231.html
Copyright © 2011-2022 走看看