主席树 笔记

博客观赏效果更佳

对于现在的我来说,只要有“可持久化”这个标签,一定伴随着 “毒瘤“,毕竟我刚学会…

好的首先介绍一下主席树是啥。主席树是“可持久化线段树”(Persistant Segment Tree)的中文民间俗称。不知道是因为有人把 Persistant 看成了 Presidant,还是因为它的发明者是 HJT(和某一任国家主席简称相同),被叫做“主席树”。

但是,可持久化是啥呢?

可持久化是啥

可持久化是亿点小优化,当你要开 n n n 个线段树,但是线段树之间只差一次修改的时候,把空间复杂度降到 O ( n log ⁡ n ) O(n\log n) O(nlogn)

如何优化呢?考虑我们现在要对一个单点进行修改,那么我们能影响到的位置(就是这个点以及它的祖先),一共才 log ⁡ n \log n logn ,个而其它位置都一样,所以我们可以 只新建 log ⁡ n \log n logn 个位置,整一个副本出来,其余位置直接继承原树即可。

蒯一张图举个例子, n = 5 n=5 n=5,修改了第四个点:

原作者

原博客

(侵权删)(私信 3348064478@qq.com)

这样就能节省下超级多的空间!

但是,有利总有弊。这样的结构破坏的原来线段树的编号的完美特性,不能再用 index<<1index<<1|1 来访问左右儿子了。我们要在线段树中多维护两个元素,左儿子和右儿子的编号。

经典题型

静态/动态区间第 k k k 位:给定一个序列,每次给出 l , r , k l,r,k l,r,k,求 [ l , r ] [l,r] [l,r] 中的数排序后,第 k k k 个位置的数是谁。(当然,我们不会实际去排序,所以询问操作对原序列没有影响)

如果是动态的,那你还要支持单点修改的操作,会给定 x , y x,y x,y,要支持把第 x x x 个位置上的数改成 y y y

(假设我们离散化过了所有 a i a_i ai,和所有询问修改后变成的 y y y

静态的问题

板子见 洛谷 3834

对于一个查询 ( l , r , k ) (l,r,k) (l,r,k) ,(假设我们能)把 a [ l ⋯ r ] a[l\cdots r] a[lr] 拿出来建一颗权值线段树 T T T,查询就很容易了:把区间分成左半部分和右半部分,设左半部分中数字的个数为 l s u m lsum lsum。如果 k ≤ l s u m k\le lsum klsum,那么就在左半部分中查找,否则就在右半部分中查找第 k − l s u m k-lsum klsum 个。

但是我们怎么把 a [ l ⋯ r ] a[l\cdots r] a[lr] 拿出来建一颗权值线段树呢?这个时空复杂度都是 O ( n l o g n ) O(nlogn) O(nlogn) 每次,再乘一个询问次数,肯定炸。

但是我们发现,线段树满足一种微妙的“可减性”:我们考虑建 n n n 颗线段树 T T T T i T_i Ti 表示 a [ 1 ⋯ i ] a[1\cdots i] a[1i] 组成的权值线段树。然后 a [ l ⋯ r ] a[l\cdots r] a[lr] 组成的权值线段树的对应位置就是 T r T_r Tr 的对应位置减去 T l − 1 T_{l-1} Tl1的对应位置。但是把 T T T 建出来,光空间就够炸的了,是 O ( n 2 ) O(n^2) O(n2)

考虑用上面“可持久化”的办法来优化求 T T T 的过程: T i T_i Ti T i − 1 T_{i-1} Ti1之间,差的只是在(离散化后的) a i a_i ai 位置上加一。那么我们就让 T i T_i Ti T i − 1 T_{i-1} Ti1 的基础上,复制其中的 log ⁡ \log log 条链即可。这样就可以空间复杂度 O ( n log ⁡ n ) O(n\log n) O(nlogn) ,时间复杂度 O ( n log ⁡ 2 n ) O(n\log^2 n) O(nlog2

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 11
    评论
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值