浅谈主席树

可持久化数据结构

可持久化数据结构就是支持历史询问的数据结构。比如一共有(5411)次操作,我问你第(251)次操作之后这个数据结构长啥样,你能在约束的时间空间内回答出来就算支持了可持久化,否则就不算。一种很××的做法就是每次更改构之后我都把它保存下来,然后你问哪次我就去哪次里面找就是了。但是这显然不优秀。然后前辈们发现,每次修改只会让该数据结构某部分与之前不同,那就只需要记录这不同的部分就行了。

主席树

主席树就是可持久化线段树,是函数式线段树(别问我函数式是啥意思我也不知道),如果你还不会线段树请出门左转。对于每次修改,我们只需要把该次修改所改动的结点新建一遍,其余的结点跟上一历史版本一样即可。如果每次都是单点修改的话,那么就只会增加(logn)个新结点。由于动态开点的原因,左右儿子就不能通过完全二叉树找左右儿子那种方式来找了,必须要记录自己的左右儿子编号。

假设当前主席树是前(i-1)次操作之后的成果,根为(root[i-1]),一共有(tot)个结点,现在要进行第(i)次操作。

1、令(root[i])=(++tot),(p=root[i-1],q=root[i])

2、如果要修改的点在左儿子子树内,并且(p)不为(0),那么就令(q)的右儿子等于(p)的右儿子。然后新建一个点给(q)当左儿子,(q=ls[q],p=ls[p])。右儿子以此类推

3、如果到这条修改路径的底端则回溯更新结点信息,否则重复第二步。

这样子建出来的主席树,从(root[i])开始访问,就可以访问到(1)(i)次操作之后的数据结构了。因为每次只会新建(logn)个结点,所以空间复杂度只会随着修改次数缓慢增长,而线段树作为主席树的本质内部结构,时间复杂度也能过关,就这样,主席树就建好了。但是如果要区间修改的话,还需要一些骚操作,这里就不讲了。

原文地址:https://www.cnblogs.com/AKMer/p/9956734.html