zoukankan      html  css  js  c++  java
  • 权值线段树 学习笔记

    权值线段树 学习笔记

    权值线段树可以用来代替平衡树的一些操作,如果不知道平衡树是干什么用的,请先学习平衡树。

    首先,我们想一下线段树可以干什么??

    区间加,单点加,区间和……其实还有很多操作,只不过权值线段树一般只用到这几个比较常见的操作。

    权值线段树的实质是对值域建线段树,权值线段树对值域中的每一个值都建了一个叶子节点,所以建树时间复杂度是 (Theta (nlog_2 [l,r]))([l,r]) 是值域。单点修改,插入就是 (log_2[l,r])

    考虑平衡树的添加一个数,因为值域中的每一个值都对应一个叶子,所以我们直接找到这个叶子节点,将它的数量加 (1) 就可以了,删除一个数同理。

    求第 (k) 大和平衡树差不多,如果 (k) 小于等于左儿子就递归左子树,大于就递归右儿子,同时 (k) 减去左儿子的大小。

    (x) 为第 (k) 大也和平衡树差不多,如果 (xle mid) 就递归左子树,如果 (x>mid) 就递归右子树,同时 (k) 加右子树的大小。

    因为值域一般比较大,而空间复杂度是 (Theta([l,r])) ,很多题目会炸掉,所以一般采用两种方法来优化。

    第一种方法是离散化,将所有操作的数据离散化为 ([1,n]) 然后在 ([1,n]) 建树,每次操作实际修改离散化后的值,只适合可以离线的题目,但是这种方法无论是时间复杂度还是空间复杂度都优于第二种,而且写法简单。建树 (Theta (nlog_2n))(n) 是数据范围,单次操作时间复杂度为 (Theta (log_2n)) ,空间复杂度为 (Theta (n))

    第二种方法是动态开点线段树,这种方法虽然在很多方面不如第一种,但是可以在线。考虑在值域中二分每次要操作的值,只需要 (log_2[l,r]) 的时间复杂度,所以我们考虑每次把二分用到的点在线段树上现用现开,这样就可以实现在线操作。所以建树时间复杂度为 (Theta (nlog_2[l,r])) ,单次操作为 (Theta (log_2 [l,r])) ,空间复杂度为 (Theta (nlog_2[l,r]))

    但是需要注意的是权值线段树只能维护正数,不能维护负数,所以在处理负数的时候要统一加一个基数。

    几道例题。

    (luogu P1168)中位数

    直接离线权值线段树,然后不断加数在 (i) 为奇数的时候维护第 (i/2+1) 大就可以了。

    代码

    (luogu P2234 [HNOI2002])营业额统计

    离线或者在线每次差插入的数是第 (k) 大,然后再查 (k-1) 小或者 (k+1) 小在减一下,取个 (min) 就可以了。

    代码

    (luogu P1486 [NOI2004])郁闷的出纳员

    维护一个全局 (tag) 在每次全局加减的时候对 (tag) 进行操作,然后在删除的时候对 (min) 进行一个 (tag) 的逆运算,把小于等于逆运算后的数区间删除,因为加入权值线段树的值是不变的,但是 (tag) 是不断变化的,所以我们对当前的操作的数进行一个 (tag) 的逆运算,就是权值线段树中要操作的数字。插入也要进行一个 (tag) 的,然后每次直接查第 (k) 大就可以了。

    需要注意的是因为进行 (tag) 逆运算可能有负数,所有这道题目需要统计加一个基数,然后输出的时候再减掉基数。

    代码

  • 相关阅读:
    如何管理和优化日益增长的代码复杂度?
    groupcache-readme-go
    shell脚本的桩
    软件的模块化开发
    ldd命令--查看命令依赖的库文件
    链接
    LDD命令--可执行文件依赖的库出现错误时
    开源日志系统 log4c 使用心得+总结
    SDOI2018R1划水记
    BZOJ1009:[HNOI2008]GT考试(AC自动机,矩乘DP)
  • 原文地址:https://www.cnblogs.com/last-diary/p/11544625.html
Copyright © 2011-2022 走看看