动态点分治

原理

动态点分治模板题。。说实话动态点分治有点像(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))

幻想乡战略游戏

好像也挺板子的,但是我不会

先建立出点分树,按照套路求出数组(sum[u])表示(u)子树内的权值和,(dis1[u])表示(u)子树内点到(u)的贡献和,(dis2[u])表示(u)子树内点到(f[u])的贡献和

然后从点分树的根开始寻找答案较大的点走

原文地址:https://www.cnblogs.com/knife-rose/p/12431266.html