线段树-Count on a Treap-神题

Count on a Treap

题目来源

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

问题提出

什么是Treap

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

问题

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

保证 k e y key key, w e i g h t weight 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) dist(u,v)=dep(u)+dep(v)2dep(lca)

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

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

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

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

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

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

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

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

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

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

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值