洛谷P4211 [LNOI2014]LCA

P4211 [LNOI2014]LCA

完整题面

在这里插入图片描述
这道题的提议也是够简洁的了,不过是真的挺难想的
一、.想正解先想想暴力怎么做:对每次询问,依次枚举每一个[l,r]范围内的点,求LCA(i,z),将深度加到一起
然后要想优化这个过程,一种思路是加快求lca的速度,但是这样做最多能优化到单次O(1)查询,总体是O(m*n)级别的;另一种思路是从lca下手,枚举每个点作为lca的贡献,目标复杂度是O(n *log2 (n))(这道题n,m同阶。就都用n表示了)。
注意到可以离线,有没有用再说
二、第一步的问题转化完成后,开始沿着思路二思考。看到树看到区间,想想我能掌握的可能用得上的知识点(或是勉强掌握的):树剖,点分治,差分/前缀和,lca及其性质
点分治应该是用不上了,因为这个问题与树的形态有关
然后思考lca本身的性质,我们发现所有可能成为lca的点都在z到根节点的路径上,这就是说我们要考虑的所有点在一个链上。
接下来我们将[l,r]中每一个点到根节点的路径上所有点的贡献值都+1,然后再从z开始将z到根节点的路径之间的所有点的贡献值累加,就得到了答案。然后我们考虑加速这一过程,不难想到要用树剖。目前单次询问的复杂度是O(n *log2 (n))的,并且每组询问回答完之后还要清空线段树,还需要进一步优化,尽量少删除点或者不删除点。
三、想不下去了就看看还有什么可能没有尝试:差分/前缀和,离线。
首先考虑将问题差分,分成[1,l-1]和[1,r]两个区间,然后两个区间贡献的差就是这个问题的答案,那么拆分后的每个询问就只与一个点有关。接下来思考如何不删除点,发现不同询问之间共用相当多的点。这时经验就发挥作用了:将拆分后的询问排序,按编号升序枚举点,并把这个点到根节点路径上的每一个点的贡献值+1,然后回答在这个点上的询问。整个算法的时间复杂度就是O(n *log2 (n)),符合我们的预期复杂度。

倒确实没用什么高级的东西,但是思维链真的是够长的了,是个好题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值