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

    主席树乱讲

    前置技能

    • 线段树:动态开点,标记永久化,基本操作
    • 离散化

    介绍

    主席树即可持久化线段树,也叫作函数式线段树
    至于为什么叫做主席树,据说是一个叫HJT的神犇在考场上现场yy出来的
    可持久化线段树:
    顾名思义就是线段树经过了若干次修改之后,仍然能找到原来某次修改前的线段树的信息的一种数据结构

    建立

    最暴力的方法就是,每次修改就复制当前的线段树新建下一版本的一棵树,在上面修改
    空间复杂度(O(mnlogn)),时间复杂度(O(mnlogn))
    这样并不高效,还不如不用

    进行优化

    • 考虑单点修改
      线段树单点修改只会修改一条链,即(log)个点,其它的点不变
      那么我们为什么不可以把其它不变的点继续利用?
      所以我们就可以只新建这条链的点其它的点直接接上去就行了
      那么空间复杂度就是(O(nlogn)),时间复杂度(O(nlogn))
    • 考虑区间修改
      如果像单点修改那样,新建改变的节点
      那么区间标记不好进行(pushdown)
      标记永久化,这个常数小,空间小,又快又方便
      这个好,加上标记永久化就解决了

    记得要用动态开点线段树

    单点修改模板题Luogu3919
    区间修改模板题SPOJ/Vjudge


    用法

    不要尝试用整体二分等离线算法水过去强制在线

    1. 区间第(k)小(大)问题

    Luogu静态区间第k小模板题
    给定(N)个正整数构成的序列,(M)组询问,对于指定的闭区间查询其区间内的第(K)小值

    (N,M<=2*10^5)

    做法

    区间第(k)小这一类算是比较套路了
    考虑如果查全局第(k)
    可以开一棵值域线段树,维护数的个数
    把数字离散化之后丢进线段树中去
    然后直接在线段树上二分数字
    如果(k)大于当前点左子树的点的个数,那么(k)减去这个个数,去右子树
    否则去左子树

    这道题的做法:
    类似
    把数字离散化,主席树为值域线段树,维护数的个数
    从第一个数字开始不停的往主席树中加点,每加一个数字,就新建一个版本
    那么第(i)棵线段树保存的就是前(i)个数字
    查询区间([l,r])(k)小?
    和全局第(k)小的做法一致,但是我们要找的只是数组([l,r])中的数
    之前说过第(i)棵线段树保存的就是前(i)个数字
    那么运用前缀和的方法,把第(r)棵线段树和第(l-1)棵线段树作差,得到的就是这个区间内的数,其它的都和全局第(k)小没有区别

    此时树就像是一个二维平面
    横纵坐标分别为树的版本和每一棵树

    提一下:如果要做动态的区间第(k)小,即带修改,要用到树状数组套线段树来做,思路很相似,就是把数组区间那一维用树状数组来维护

    2. 树上路径第(k)小(大)

    Bzoj2588Count on a tree
    一棵(N)个节点的树,每个点有一个权值,对于(M)个询问((u,v,k)),你需要回答(u)(v)这两个节点间第(K)小的点权

    (N,M<=100000)

    做法
    主席树还是为值域线段树,维护数的个数
    每个点的线段树版本由它的父亲加入它的点权得到
    那么每个点的线段树存的就是它到根的所有点的点权
    还是树上二分数字,还是线段树作差:
    假设(u, v)的LCA为(x),用(rt[i])表示(i)这个点的线段树
    那么就是这样作差
    (rt[u]+rt[v]-rt[x]-rt[fa[x]])
    这样就只包含了(u,v)路径上所有的点了

    3. 区间中位数

    HDU4251
    给定(N)个正整数构成的序列(A),将对于指定的闭区间查询其区间内的中位数的值

    (N,M<=100000,A[i] in [1, 10^9])

    做法
    (emmm...)
    这不就是区间第长度除以(2)小吗?

    4. 区间不重复的数的个数

    SPOJ3267
    给定(N)个正整数构成的序列(A)(Q)组询问,于指定的闭区间查询其区间内的不同的数的个数

    (N,Q<=30000,A[i]in[1, 10^6])

    做法
    不是权值线段树
    维护位置
    如果插入一个数时发现之前有过了
    那么修改当前的,那个位置(−1)
    然后插入这个数字,在相应的位置(+1)
    询问([l,r])就是第(r)棵线段树中([l,r])的区间和

    5. 区间前(k)小(大)的和

    好像没有找到题诶。。。
    给定(N)个正整数构成的序列,将对于指定的闭区间查询其区间内前(k)小的数的和
    (N,M<=100000)

    做法
    先求第(k)小,答案就是它和它子树的点的值的和
    也就是主席树再存下每个点离散化的值,维护值的和就好了

    一些其它的就不列举了

    主要是没什么了,而且其它的基本上方法差不多

  • 相关阅读:
    成幻Online Judge 1.00 Beta 环境配置
    AJAX Control Toolkit tabs 的纯Javascript演示
    Microsoft ASP.NET Futures (July 2007)中History在客户端的使用(即不必安装ASP.NET Futures)
    HTML中利用纯Microsoft Ajax Library做出可调用WebSerives的AutoComplete
    初雪,小词一首
    vs 2008中使用Asp.net Ajax智能感知Intellisense
    IE6下Ms Ajax Lib 调用Ajaxtoolkit时Common_InvalidPaddingUnit未定义的解决方法
    由成幻OnlineJudge学习如何做自己的AcmIcpc在线评判系统-5.在线编译与测试系统代码粗解
    成幻Online Judge 1.00 源代码下载 [20070804]
    Asp.net中动态在中加入Scrpit标签
  • 原文地址:https://www.cnblogs.com/cjoieryl/p/8486012.html
Copyright © 2011-2022 走看看