【平衡树启发式合并】POJ1741[Tree]题解

题目概述

给出一棵树,求dis(x,y)<=K的点对(x,y)有多少,dis(x,y)表示x到y的最短距离(x<y)。

解题报告

这道题是明显的点分,就不阐述点分了,主要讲讲另一种解法:平衡树+启发式合并,效率也很不错:O(n*log2^2(n))。

说的这么高大上,实际上就是暴力啦。先找出根节点,然后Dfs递归处理。对于每一个节点,都建立一棵平衡树(作者蒟蒻,这里使用Treap),然后从叶往根上推(从叶往根上推根据Dfs的深度优先就可以轻松实现)。举个例子,如图:
这里写图片描述
首先先把son1的Treap的所有节点(直接遍历即可)和fa的Treap进行累加,累加后,把fa加入当son1中。处理完毕后,根据启发式合并的思想,先比较fa的Treap的平衡树大小和son2的Treap的平衡树大小,把小的往大的身上累加,然后把小的加入到大的中。以此类推,直到处理完所有son。

但是如何计算两个点之间的距离?其实很简单(当然也可以直接用lazy_tag,留给你们自己思考啦:P):
这里写图片描述
记录dis[i]表示i节点在这棵树中的深度。由图所示,son1和son2的距离就是dis[son1]+dis[son2]-2*dis[fa],不难发现2*dis[fa]可以独立领出来统一减去,那么问题就简化为dis[son1]+dis[son2]了。
ps:这样的话,就有一个细节了:fa不能在刚开始就加入Treap,否则统计会出错(fa和其他节点的距离是dis[son]-dis[fa],减去2*dis[fa]会出错)。

其实至此,这道题目就讲完了,再来谈谈启发式合并复杂度的问题:由于是小的加入到大的身上,所以原先小的树的节点所在的树的个数必定*2,而树的个数最多是n。所以每个节点顶多被加入log2(n)次,而每次加入的复杂度是log2(n),所以总时间复杂度为O(n*log2^2(n))。

示例程序

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值