【题解】P3920 [WC2014]紫荆花之恋

思路

点分树 + 根号重构 + *高速平衡树。

点分树的两种常见用法无非是 直接做和路径有关的暴力 还有 处理这种有关单点和整树的问题,后者的另一个经典题目是 P3241 [HNOI2015]开店。

回到这个题目,处理路径考虑先上点分治,暂时不考虑强制在线的限制。

因为每次加上一个新点,所以可以考虑在加点的过程中动态维护答案,于是问题变成维护每次加点之后答案的增量。

也就是说对于新加入的点 u,每次询问原树中满足 dist(u,v)ru+rv 的点 v 的个数。

等式变形成 dist(u,v)rurv,似乎不太好在点分的过程中处理 dist(u,v).

一般情况下考虑的是把 u,v 之间的路径拆成 {u,,lca(u,v)}{lca(u,v),,v} 两部分,但是 lca 在点分的过程中难以钦定。

又因为实际上可以从路径上的任意一点断开,所以可以联想到点分树的一个很好的性质:点分树上两点的 lca 在原树中一定在这两点的路径上,并且点分树的树高是 O(log) 的。

这意味着我们可以从点 u 向上枚举 lca 然后处理点 v 的个数。

先考虑静态询问怎么做。假设当前枚举到 u 的祖先 x。原式可以化成 dist(u,x)+dist(x,v)ru+rv,调整成关于 v 的限制就是 dist(u,x)rurvdist(x,v).

注意到等式的左边在枚举祖先的时候可以视作一个定值,于是我们只需要知道 x 的子树中满足 rvdist(x,v) 大于等于某一个定值的点的个数就可以了。

常规的树论做法都不太可行,考虑一些和点分树性质有关的暴力。

因为点分树的树高是 O(log) 级别的,所以对于每个结点大力存储下它子树中信息的总复杂度是 O(nlogn).

这意味着我们可以预先将 x 子树中所有的结点的 rvdist(x,v) 用某种神秘的数据结构维护一下,之后询问就是在上面查询的事情。

因为动态加点没法离散化,所以选择用平衡树实现。

注意到向上枚举的过程中会算重子结点的子树,所以还需要维护 rvdist(fax,v) 用来容斥。

然后再考虑如何维护动态插入结点。

不考虑点分树的性质,那么直接将新点接在原树父亲下面就行,可以看作是钦定在父亲处点分一次,然后在这个孤点在进行一次点分。现在的问题是这样做不能保证复杂度。

于是考虑类似替罪羊树的思路,当某棵子树失衡的时候就暴力调整。钦定一个比例系数 α,如果插入点 u 后其祖先 x 满足 size(x)αsize(fax),就直接暴力重建 x 的子树。

具体的复杂度就是调参,α0.8 左右的时候点分树的树高大概还是 O(log)(但我不会证,有懂的老哥麻烦教一下

如果要再偷懒的话可以不写平衡树,用 vector + 根号重构平替。具体考虑维护两个 vector,一个当作缓存池存当前加入的数据,另一个用来存溢出的数据。当缓存池超过根号大小的时候就暴力归并。

查询直接在 vector 里二分。

这个在很多阴间根号题都有应用,O(nn) 应该比较快。

复杂度懒得算了,反正常数已经挺离谱了。

代码

posted @   kymru  阅读(46)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示
主题色彩