题目大意
给出一棵
n
个节点的带点权树,要求实现
- 将
x
到
y 路径上的所有点的权值都加 c - 询问
x 到 y 路径上所有点的权值的最大公约数。
思路
首先有一个比较显然的结论
gcd(a1,a2,...,an)=gcd(a1,|a2−a1|,...,|an−an−1|)
其中
∀i>1,ai≠ai−1
我们只需要证明
n=2
时成立,剩下的就可以用归纳法证明了。
设
g=gcd(a,b)
,不失一般性地,我们令
a<b
那么
a,b
可以写成
a=k1g,b=k2g
则
b−a=(k2−k1)g
,也就是说
g|(b−a)
接下来我们需要证明不存在比
g
更大的公约数。
假设
那么
于是
a,(b−a)
分别可以写成
a=k3g′,(b−a)=k4g′
则
b=a+(b−a)=(k3+k4)g′
b
也是
因此当
n=2
时得证,当
n>2
时归纳地证明即可。
有了这个结论这个问题就可以得到化简了。我们不妨先看一下这个问题在链上的情况。
我们不妨用线段树来维护原序列的数,以及差分序列每个区间的最大公约数。那么对于查询操作我们只需要查询开头节点的权值以及某一段的差分的最大公约数即可即可。对于修改操作,对于点的权值的维护就是简单的区间加法了,对于差分的维护我们只需要修改对应区间的头尾两个点即可。
既然这个问题在链上可以简单地解决,我们可以借助树链剖分将链的情况拓展到树上。对于每条重链上我们用维护链的方式来维护,而查询或修改的时候分开为若干条重链,用维护链的方式分别修改每段重链上的线段树。
但是这里有个新的问题诞生了。假如我们现在需要修改
u
到
注意到对于原序列的操作只有区间修改和单点查询,使用树状数组可以优化常数。
至此,这个问题大致上就被解决了。
时间复杂度:
O(nlog2n)
空间复杂度:
O(n)