【填坑】可持久化线段树解决无修改的区间k大问题

区间k大问题是一个比较经典的问题,各种方法层出不穷,写暴力的、树套树的、主席树的、分块大法好(@LOI_DQS)的……
这里讲一下权值线段树+可持久化解决的方法(不支持修改操作)
首先是权值线段树,顾名思义,就是按权值大小保存而不是按照序列顺序保存的线段树,如1,4,2,5,3,在权值线段树里保存的顺序应该为1,2,3,4,5
可持久化数据结构,就是指可以“持久”的数据结构,具体就是假设你现在做到了第100步,却突然想查询第50步时的状态(听起来很坑对不对)
可持久化如何实现呢?想具体了解的可以看wc2012 FHQ的论文《谈谈各种数据结构》,大概比较靠后的位置;不想具体了解的可以看我讲的……

Q:可持久化最简单的实现方法是什么?
A:[手动斜眼]每次操作后的数据结构存一遍,操作N次就存N棵树
Q:说的吼!但是空间太大了怎么办?
A:……
Q:一个数据结构修改要动多少东西?就拿线段树说吧
A:修改一次要改logN个节点的值
Q:那么剩下那些不用改的节点还用存吗?
A:……似乎不用了
Q:那么修改一次就等于把所有修改的节点另建立新节点,对吗?
A:我好像明白了些什么…………

这里写图片描述
黄色节点为要修改的节点,红色节点为新建的节点,黑色圈里圈着的是旧树,红色的圈里圈着的是新树,可以看到,修改后的新树只是在旧树的基础上修改了几个节点,所以只需要新建这几个节点,并把新树的部分指向指回旧树

这个就是可持久化的实现方式了,那么,可持久化和权值线段树怎么解决区间k大问题呢?
首先把值全部排序去重,用于建权值线段树,可以用stl中的sort和unique解决……权值线段树里保存的内容是值的数量,比如插入三个3就记录为3,再然后按照序列顺序依次插入节点,由于这是可持久化线段树,所以请用可持久化的方法插入……
什么,你说线段树不支持插入?你开始建棵空树啊,反正你都知道权值了,照着往下找,把插入改成单点+1不久完了吗?

然后就到了查询了,首先因为你是可持久化的,那么查询l到r区间就是你第r次插入减去第l-1次插入后的线段树的样子,想想对不对,可持久化后你总共建立了n棵线段树,两棵线段树相减,得到的就是一棵只有中间过程的线段树,在这里也就是第l次操作到第r次操作了

那么我们得到了这个区间,就可以继续找第k大了,怎么找?因为这是权值线段树,所以是排好序的~,

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值