初始主席树

 

•参考资料

  [1]:树状结构之主席树

  [2]:主席树入门详解+题目推荐

  [3]:主席树 by 孤独·粲泽

  [4]:主席树(入门篇)

•抛出问题

  给定 n 个数,m 次操作,操作类型有:
    (1)在某个历史版本下的单点修改;
    (2)输出某个历史版本下某个位置的值的值;
  其中 $n,m\leq 10^6$;

•问题的解

  这类问题,一般可以通过主席树解决;

  因为每次操作只改变单点的值,那么形成的新版本较当前的版本而言,只是改变了某条链;

  而线段树中,最长的链的节点个数不超过  $log_{2} n+1$,所以只需改变这 $log_{2} n+1$ 个节点的信息即可;

  而其他节点均可重用之前版本的节点信息;

•相关题目

  上述问题可以参考这道题目:洛谷 P3919 【模板】可持久化数组(可持久化线段树/平衡树)

  题目解析的话,参考这篇博文:P3919 【模板】可持久化数组 -初步探究主席树

  在博主巨巨的影响下,我的代码风格顺利同步过去;

•Code

  洛谷3919.cpp

•另一类问题

  给你 n 个数,m 次询问,每次询问 [l,r] 区间第 k 小的值;

•问题的解

  这或许是主席树的经典题目吧;

  建立 n+1 个线段树,每个线段树维护一个前缀和,并用 rt[] 记录第 i 个线段树的根节点;

  询问的时候,只需要将 rt[ r ] 与 rt[ l-1 ] 做差即可;

•相关题目

  与此相关的一道题目为:HDU2665 Kth number

  题干要求是求第 k 大,但实际求的是第 k 小,按照求第 k 小的思路求解即可;

  推荐博客:树状结构之主席树

•Code

  HDU2665.cpp

•进阶题目(HDU4417 "Super Mario"

  给你 n 个数,m 次询问,每次询问 [l,r] 中有多少数小于等于 k;

•题解

  和上一个求区间第 k 小的题目相仿,只不过在查找的时候不同;

  定义 $query(l,r,pos,k)$ : 以 pos 为根节点的线段树中,小于等于 k 的总个数;

  $ans = query(0,siz,rt[r],k) - query(0,siz,rt[l-1],k)$;

  因为存在 k 小于任意一个数的情况,所以建树的时候从 0 开始,即 $build(0,siz,1)$;

  siz : 将 n 个数去重后的数的个数;

•Code

  HDU4417.cpp

•踩坑

  1.b数组去重后的大小为 siz,不管是建树,还是更新或查询,最大范围为 siz 而不是 n;

  2.查找 k 所处的位置是用 $upper_bound()-(b+1)$,因为 b 中可能不包含 k;

posted @ 2019-08-30 08:10  HHHyacinth  阅读(87)  评论(0编辑  收藏  举报