点分治
基础操作
点分治的应用范围非常广泛,条件有:与根的位置无关,一般为链信息统计
话说才知道点分治找重心子树大小要重新统计~
基础的二维偏序,由于具有加减性,把同一子树内的答案容斥掉即可
首先是传统的点分治做法:
由于每个节点分别统计不好实现,于是考虑对颜色进行维护
设 表示颜色 出现的路径条数,那么统计 解决了子树外的贡献
同时,对于根到当前节点上的颜色,应当产生的贡献为 ,同时应当考虑对于已经计算过的颜色应当标记而不重算
一个非常巧妙而优秀的做法:
首先对于每种颜色,可以统计为把这种颜色的节点全部删去,那么不同连通块之间都是能产生 的贡献的,那么每个节点的答案应当增加 所在连通块大小
考虑将这一信息保存在每个连通块最浅的节点,遍历时可以方便地取用
由于每个节点只有一个父亲,那么只会存一个信息
当然,直接算会算重,那么应当记录这种颜色上一次的值为多少,进入时更改,退出时还原
对于当前联通块的大小,即为 子树内这种颜色的大小之和,一遍 即可
- 可以发现,无论哪种方法都需要对每种颜色分别处理,这种思想是关键
可以发现这个的棘手之处在于 操作没有加减性,于是需要不断进行结构的合并操作
假设之前子树内的所有路径信息已经维护出来,那么对当前子树的所有路径进入查询
如果路径按照从浅到深加入,那么其余的合法区间也在单调移动
那么此时对于位置来说最优性有保证,可以用单调队列维护
由于接口处答案的统计方式不同,需要对当前颜色,和不同颜色维护两个单调队列
这样发现每棵子树需要把之前深度都遍历一遍,那么把所有子树按照深度排序后来做复杂度就对了
然而目前还没有卡过去常……
另一种做法是把信息统计都线段树上然后进行合并,听着比较难写~
P4183 [USACO18JAN]Cow at Large P
考虑将牛牛初始的位置作为根,那么对于一个子树,在她跑进子树之前完成拦截即可
考虑子树内放置在最浅的叶节点一定最优,这个距离设为
那么一个子树的拦截有效当且仅当
考虑更浅的节点的有效拦截可以直接取代其子树中的所有拦截
那么放置个数=
考虑优化,发现此时表达式不满足了无根性质(即)
可以通过一个非常巧妙的构造来消除掉这个影响:
考虑如果将所有满足条件的(不仅仅是恰好最浅的)都产生贡献就可以消除,但是会多出来
为了将所有贡献和设为 ,将每个点的权值设为 ,此时子树和为
公式上因为 (即一条边贡献两个度数,减去最祖先上面的边)
可以理解为节点的贡献都在 处被消除
此时便可以当做偏序问题用点分治解决了
首先的是暴力的 ,
唯一棘手的地方就是转移区间的限制,如果在链上可以使用 分治,在树上就使用点分治
保持树的有根性,对于每个分治中心,先去 中心以上的部分,那么此时子树的祖先都已经 完成,那么将子树中的点按照深度排好序并将祖先依次加入候选集合即可
另一个比较妙的方法是维护每个节点的出栈序,然后直接在自己和祖先的区间查询即可,此时恰好其它节点都没有加入(祖先子树要么是之前遍历不在区间中,要么是在区间中但还遍历到)
按重心转移
一类问题是要求选择树中的一个点以满足最值条件,往往可以根据性质的单调性不断跳跃至连通块重心来实现,需要满足价值函数沿着树的某个点的方向单调进行
选择取决于最长路径,所以很显然是单调的
于是先选择重心,去判断最大值在哪个儿子,此时最多只有一个更优,向那个儿子跳跃即可
有性质凸函数之和还是凸函数?
设重心在 这条边上,离 的距离为 ,则总贡献为
其中 为距 的距离
此时的大小仍不好比较,那么考虑求导后大于零的 是更优的,向着那个子树移动即可
类似的是幻想乡,只不过带修放在后面吧
边分治
一直以为边分治木有用,再学一边才发现其实用处大得很,只不过又难写又难调,但凡出来都是大毒瘤,写出来的概率实在太低……
先介绍一下过程:
与点分治类似,找到一条边尽量把树分得均匀,然后递归进行
但是边不具有均分性,遇到菊花就完蛋了,于是需要一个三度化的过程,类似于儿子兄弟表示法把整棵树转化为二叉树去做
然后是优缺点:
边分治的应用范围略为狭窄,要求能三度化,即新加入的边不能影响答案,比如数颜色等就不太适用了
除此之外并无缺点(可能难写算一个),其关键在于一个分治中心只对应两个子问题,于是许多 算法的复杂度是适用的,最关键的是边分树是二叉的,允许了出题人进行可持久化、合并等一系列操作……
基础题并不多(好吧是我写的不多),大多数都是点边共用的,就不放了
询问是一个常见形式,即转化为 和减 性质,其中 的部分可以通过经典的到根路径加操作以及到根询问来实现,可以维护出每条边被经过的次数
具体而言,由于边分树上一个点是一条边,原树点都在叶子上,然后枚举其所有祖先,答案就是 ,其中表示的是除 以外的子树内
而询问的是一个区间,那么用主席树来维护出区间信息即可
考虑修改操作,直接把第 棵主席树重建即可
点分树
简单而言就是根据选取重心的关系连边建树
具体实现上发现与其父亲距离可以点分治顺便算出,而不用累哼哼写个 还跑得慢……
点分树上维护的信息关键都是围绕容斥本棵子树展开的
对于本质,点分树其实是对于树的一种分割方式,但是十分平衡
对于点分树上一个点只要跳父亲就可以得到树上全部的信息
但是一定注意点分树的父子关系非常弱,没有任何加减性!
还是这个比较经典~
设 表示 子树内与 距离小于等于 的个数
表示 子树内与 距离小于等于 的个数
那么答案就可以统计为 了
对于修改,也直接暴力跳即可
由于平衡性,类似于启发式合并的分析,点分树子树的 和是 级别的,直接动态开点是可以接受的
同时保存 和
那么一个祖先(及对应的边)的贡献就是子树 子树 边权
这个实际上是刚才说的那个套路,但是带了修改
跳跃子树的过程转化为转移到儿子上
而权值的快速计算和上一道题几乎一样了
个人认为(欢迎指正)如果用边分树可以更一般化,儿子的数量与复杂度就无关了
设 ,考虑往表达式中加入构造
由于后半部分是定值,成功把二次降为一次
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效