关于可持久化线段树的一些研究(链表实现)

    xiaoxiao2024-12-29  11

        本人蒟蒻一只……近日终于弄懂了可持久化线段树的一些东西……写下来分享一下=w=

        首先要谈可持久化线段树,你肯定得懂线段树吧。这里就不提线段树了……可持久化线段树是什么东西呢?就是对线段树的叶子节点做m次修改,同时做n次询问,但这些询问会问你的东西是做了第i次修改时XXXXX。举个例子,给你一列数,a1,a2,a3...an,给定两种共m个操作:1、修改一个数的值;2、询问做了第k次修改后,第i到第j个数中最大的是多少(保证已经做了至少k次修改)。(n<=100000,m<=100000)

        如果无视掉第二个询问的第一句话(第k次修改后),那么题目还是很水的啦=w=,不过加上似乎就有些问题了。但我们可以用一个笨办法!什么呢?就是把以前所有线段树的版本全部都记录下来。这样查询复杂度和以前不变,时间什么的还是有保证的!

        但很可惜,这样你要存m棵线段树,每棵线段树至少要2n个节点,那么2*100000*100000个节点……早就不知道空间炸到哪里去了=w=。

        所以我们需要更优秀的办法。仔细观察我们就会发现,每次修改一个节点的权值,其实所涉及到的节点最多也就一条链(修改ai的权值,影响的最多也就是ai,ai的fa……),而其它所有节点的权值都没有变。比如下图序列36854252,如果修改了5的权值,那么它最多能够影响的是以绿色为底的一条链。(下图直接用左右儿子点权较大的代替当前节点点权)

        那么我们新开一棵树存白色的节点就完全没有意义了。所以对于每一个节点,我们用链表的方式将其存储下来。每一次修改我们新建一条链,同时将根节点保存下来,然后按顺序修改。什么意思呢?就是root[i],表示第i次修改后的根节点,若上图,假设5被修改了(比如本来是3),root[i]=8的左儿子节点存的就是root[i-1]的左儿子节点(也是8),它的右儿子就是新的节点5,而5的左儿子又是root[i-1]中root=8的右儿子的左儿子4,而5的右儿子是新的节点5……直到完全建成这样一条链,而我们新开的节点其实也就logn个。这样空间上就有了保证。

        不会链表的都给我面壁思过去=w=

        ……好吧是我太弱了,只会搞链表……(当然用数组模拟链表也是非常兹词的=w=)

    转载请注明原文地址: https://ju.6miu.com/read-1295100.html
    最新回复(0)