P3345 [ZJOI2015]幻想乡战略游戏
带修改带权重心
这是经典的树上寻找关键点的题目,我们使用点分治处理这个问题,因为点分治的特性,就相当于在树上二分了。但是这与倍增不同,倍增只是在链上二分,而点分治则是在整棵树上二分。
然后我们考虑如何二分,显然带权重心的位置和边权无关,并且每次只需要寻找一个点的
2
s
u
m
v
>
s
u
m
u
2sum_v>sum_u
2sumv>sumu那么重心一定在这个子树内部。也就是说有一个儿子的答案比当前点小,那么重心就在这个子树内。我们可以维护3个变量。
s
u
m
d
sumd
sumd:表示当前分治范围内
d
u
d_u
du的总和
s
d
v
:
sdv:
sdv:表示当前分治范围内
d
u
d
i
s
(
u
,
v
)
d_udis(u,v)
dudis(u,v)的总和
s
d
v
f
sdvf
sdvf:表示当前分治范围内
d
u
d
i
s
(
u
,
f
a
v
)
d_udis(u,fa_v)
dudis(u,fav)的总和
然后我们通过跳祖先节点容斥就可以计算出当前点作为重心的答案,复杂度是 O ( l o g n ) O(logn) O(logn)所以查询我们可以从根开始,然后每次遍历所有儿子,查询对应的答案,找到答案最小的,进入它所对应的子树,然后继续这个过程,知道所有儿子的答案都大于等于当前点答案那么就找到了重心。
然后我们考虑如何修改,只会影响到当前点的所有祖先节点,所以我们暴力跳祖先进行修改即可。然后这道题最好使用st表处理lca。
细节错误:
- 一定要注意循环终止条件是f[i]!=0,相当于我们每次都是处理f[i]的有关信息
- 处理的时候距离计算是dis(x,f[i])而不是dis(i,f[i])