原理
动态点分治模板题。。说实话动态点分治有点像\(dp\)很灵活
回顾一下点分治,我们发现是利用重心的性质强行把暴力次数降低到了\(log\)次,动态点分治也差不多
由于我们需要修改,那么我们可以修改一次点分治一次,所以不能暴力点分治
考虑为什么点分治可以做到优秀的复杂度?因为重心的性质,每次递归访问的不是儿子而是子树的重心
那么我们可以根据这一点,建出点分树(按点分治递归顺序),在点分树上进行修改,由于点分树一定严格小于等于\(log\)层,所以复杂度可以有保证
例题
每个点处开两个堆,一个堆用来维护向点分树下所有黑点的距离,另一个点用来标记删除(当然您直接写可删除堆也是可以的)
答案就是最大值和次大值拼起来啦~
不过这样做有可能选到的两个值其实来自原树的同一子树
所以我们再开一个堆,用来存放每个点所有原树上的儿子到改点的最大距离,选取答案的时候在这个堆里拼接
由于我们建出了点分树,所以更改的时候只需要改点分树上对应的链就可以了
我们设\(siz[0]\)是子树内点个个数,\(siz[1]\)是子树内所有点到\(u\)的距离和,\(siz[2]\)的子树内点到\(f[u]\)的距离和
对于某个点\(u\)的答案为\(siz_1[u]+\sum siz_1[fa]-siz_2[p]+(siz_0[fa]-siz_0[p])*dis(fa,u)\)
我们每个点开个\(vector\),按权值排序,将三个\(siz\)做前缀和,二分可以求出对应区间
实际操作:跳点分树的时候,如果\(p\)有\(fa\),那么\(ans-=siz_0[p]*dis(fa,u)+siz_2[p]\),如果当前点不是\(u\),\(ans+=siz0[p]*dis(p,u)\)
来源:https://www.cnblogs.com/knife-rose/p/12431266.html