【集训队作业】DGCD

题目大意

给出一棵 n 个节点的带点权树,要求实现m个操作,包括以下两种。

  • x y路径上的所有点的权值都加 c
  • 询问x y 路径上所有点的权值的最大公约数。

n,m<50,000


思路

首先有一个比较显然的结论
gcd(a1,a2,...,an)=gcd(a1,|a2a1|,...,|anan1|)
其中 i>1,aiai1

我们只需要证明 n=2 时成立,剩下的就可以用归纳法证明了。
g=gcd(a,b) ,不失一般性地,我们令 a<b
那么 a,b 可以写成 a=k1g,b=k2g
ba=(k2k1)g ,也就是说 g|(ba)
接下来我们需要证明不存在比 g 更大的公约数。
假设g是比 g 更大的公约数。
那么g|a,g|(ba)
于是 a,(ba) 分别可以写成
a=k3g,(ba)=k4g
b=a+(ba)=(k3+k4)g
b 也是g的倍数,于是 g 也是 a,b 的公约数,这与 g=gcd(a,b) 相违背。
因此当 n=2 时得证,当 n>2 时归纳地证明即可。

有了这个结论这个问题就可以得到化简了。我们不妨先看一下这个问题在链上的情况。
我们不妨用线段树来维护原序列的数,以及差分序列每个区间的最大公约数。那么对于查询操作我们只需要查询开头节点的权值以及某一段的差分的最大公约数即可即可。对于修改操作,对于点的权值的维护就是简单的区间加法了,对于差分的维护我们只需要修改对应区间的头尾两个点即可。

既然这个问题在链上可以简单地解决,我们可以借助树链剖分将链的情况拓展到树上。对于每条重链上我们用维护链的方式来维护,而查询或修改的时候分开为若干条重链,用维护链的方式分别修改每段重链上的线段树。

但是这里有个新的问题诞生了。假如我们现在需要修改 u v之间的路径。倘若在链上我们只需要修改 u ,以及v的后继的差分值就可以了。但是在树上一个点的后继为它的所有儿子节点,逐个修改肯定是不行的。但是我们发现我们只需要修改重儿子就可以了,因为我们分开为若干段重链进行查询的话永远不会用到某段重链的顶端那个点的差分。

注意到对于原序列的操作只有区间修改和单点查询,使用树状数组可以优化常数。

至此,这个问题大致上就被解决了。

时间复杂度: O(nlog2n)
空间复杂度: O(n)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值