Link
小时候写过树状数组套主席树的版本,时空。众所周知,这个空间复杂度是非常不友好的。 今天翻到jcvb巨神的博客,发现他给了一种非常interesting的做法:值域线段树套区间平衡树。研究一番,写完之后感觉很不错。
树状数组套主席树维护DFS序
Solution
众所周知,序列上的主席树可以利用可持久化实现时空的前缀和,从而解决区间K值问题。 放到树上,如果不带修改,那就可以直接用序列的可持久化线段树方法,从根节点DFS下去,在节点的值域线段树的区间,维护到路径上值在的节点个数。这样,两点的路径上,值在的节点个数,就是。套用序列的方法查询即可。 现在有了修改,显然不可能暴力重建主席树,因为一次修改会影响子树的所有的点。 等等,一次修改影响子树所有的点?不禁让人思考能否进行区间操作?然后就联想到了DFS序。没错,DFS序就是一个满足子树的所有点是一个区间的序列。 区间操作的两种办法:用兹瓷区间修改的数据结构打标记;或者差分,把区间修改变成单点修改。待修改的树上主席树是通过套一个树状数组,绝对化相对的方法来实现的。这样,线段树就不需要可持久化了,因为本来可持久化是要维护前缀和,但现在树状数组就维护了前缀和。一次修改,会修改个线段树,每个线段树修改的时间是。一个点的值至多将在个线段树出现,粗略地估计总次数,绝对不会超过。所以得到了一个时空的优秀做法。
Code
1 |
|
线段树套平衡树维护括号序列
Solution
现在考虑优化的话,主要就是要考虑压缩空间,否则太不友好。注意到,空间之所以那么大,是因为把主席树建在了内层,一个点的权值可能出现在棵线段树中,出现一次就至多带来个节点,比较浪费。 那么考虑把值域线段树建在外层,那么这一部分的空间就是。考虑如何在内层维护整个树。 用DFS序列应该就不好弄了。。涉及到路径,DFS序似乎就无力了。。。 于是祭出大杀器:括号序! 一个树的括号序,指的是每个点在进栈的时候放一个左括号,出栈的时候放一个右括号。 然后把一棵树的括号序写下来,会发现一个惊天大秘密:从第一个括号开始,到的左括号,把匹配的括号删掉,恰好可以得到从根节点到的路径! 于是就可做了: 在值域线段树的每个节点挂一个平衡树,平衡树维护所有值被覆盖的点的左括号位置和右括号位置。左括号的权值为,右括号为,这样做一下前缀和,就可以得到根节点到一个点的路径上有多少点的值在之内了!然后就可以做了。 空间复杂度。
Code
1 |
|