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