线段树-Count on a Treap-神题

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/weixin_37517391/article/details/82969226

Count on a Treap

题目来源

Codechef Feb 2014 COT5
https://www.codechef.com/problems/COT5

问题提出

什么是Treap

  • 是一颗二叉搜索树,每个节点拥有 k e y key 属性.
  • 是一颗堆,每个节点拥有 w e i g h t weight 属性

问题

  • n n 次操作,三种类型,要求维护"大根Treap"
    • ( 0 , k , w ) (0,k,w) ,插入 k e y key k , w e i g h t k,weight w w 的点.
    • ( 1 , k ) (1,k) ,删除 k e y key k k 的点
    • ( 2 , k u , k v ) (2,k_u,k_v) ,询问 k e y key k u , k v k_u,k_v 的两点在 T r e a p Treap 中的距离.

保证 k e y key , w e i g h t weight 均不相同.

问题解答

d i s t ( u , v ) = d e p ( u ) + d e p ( v ) 2 d e p ( l c a ) dist(u,v) = dep(u) + dep(v) - 2* dep(lca)

我们以 k e y key 为下标,将这个树按中序遍历展开.

显然 [ k u , k v ] [k_u,k_v] 之间最大的 w e i g h t weight 最大的点就是两点的 l c a lca .

证明:首先 l c a lca 一定在区间 [ k u , k v ] [k_u,k_v] 之间,不然 k u , k v k_u,k_v 将位于 l c a lca 的同一侧,这不可能.其次权重最大的点一定是这颗子树的根节点,这个点一定是祖先,如果它不是 l c a lca 的话,那么它的 k e y key 将大于或小于 l c a lca 形成的子树中所有的点的 k e y key ,也就是说它不在区间 [ k u , k v ] [k_u,k_v] 之间,矛盾.

至此,用线段树可以轻松维护 l c a lca .

那么如何维护一个点在树上的深度呢?

根据Treap的特殊性质,我们知道每个点的 w e i g h t weight 一定小于他父亲的 w e i g h t weight .

从这个点到根节点的祖先链上的 w e i g h t weight 是不断递增的.

这里有一个非常特殊的性质,在序列上就是从这个点往两侧各找一个直接的递增子序列,那么序列上的点都是他的祖先.

这个性质基于这样一个事实:每个点左右两侧的第一个大于它 w e i g h t weight 的点,都是这个点的一个祖先.因为其中一个点是它的父亲,而另一个点…自己画图观察一下就好了.

因此两个递增序列的长度和就是它到根的距离.

如何维护某一个点向右的直接递增序列呢.也是使用线段树,参考我的另一篇博客,楼房重建.

猜你喜欢

转载自blog.csdn.net/weixin_37517391/article/details/82969226
今日推荐