数据结构 泛做
享受一个人在机房里面调 的感受
感觉有些处理方式是很妙的
长链剖分
组合
设 为叉的下长减上长为 的方案, 为距离其长度为 的点数
直接转移是 的,使用长链剖分进行优化
长链剖分将重儿子的定义改为最长链的儿子,一个性质是树上所有长链的总和为
转移的时候每个长链的儿子显然可以继承父亲的信息,另一个令人耳目一新的操作是使用数组分配下标的方式:先开一个长度为 的数组,每次 直接分配,儿子的数组 f[son[x]]=f[x]+1,g[son[x]]=g[x]+1
剩下的都是 的转移了:
For(j,0,len[t]-1){
ans+=g[t][j]*f[x][j+1]+f[t][j+1]*g[x][j];
if(j) f[x][j-1]+=f[t][j];
}
For(j,0,len[t]-1) f[x][j+1]+=g[t][j]*g[x][j+1],g[x][j+1]+=g[t][j];
Link Cut Tree
THUWC2017 在美妙的数学王国中畅游
想到不联通显然 ,那么变成抄式子,给了泰勒展开那么维护若干项即可:
考虑 的泰勒展开:
那么复合函数求导数得到:
所以套上去就得到了 的泰勒展开的式子,也就是乘上 的若干次方
考虑 的展开
设 ,还是能得到
多求导就是多乘
那么套上 展开的式子,维护每次的系数和,剩下的都是「模板」 了
所以这题的收获是 展开科技:
ZJOI2016 大森林
考虑题设可以把它们都离线之后统一处理,那么 地用扫描线处理操作
也就是每棵树先长出来最终形态再回答询问
对于生长一个节点,直接差分,最后统一做即可
而对于更换生长点,考虑建立若干虚点表示操作,但是没有点权(真正生长出来的点有点权,为了求 )
具体而言,一开始求最终方案的时候
修改 的生长点,先对存在 号点的区间取交集
之后让新点和原来的生长点连边,再和新的生长点连边
在最后的统一处理中把虚点切掉/连上即可
平衡树
【WC2016】鏖战表达式
水高分容易 难
用可持久化 做其实十分显然,所以 是 的
在 的博客里面给出了卡掉的构造:先来一堆 ,再来一堆 ,一次类推,这样这个算法的复杂度到了
而正解用了随机化:对于 的合并,这样写:
if((ord[l]==ord[r]&&rand()%(sz[x]+sz[y])<sz[x])||ord[l]<ord[r]) balabala...
else balabala....
这样单次复杂度期望
证明?Itst说有2019/2018的论文,然而论文网址废掉了
记录两个 的手残的地方:
第二个的时候记得是
可持久化的时候 写的可持久化后的点
Codeforces702F T-shirt
一开始得到一个二分的做法,但是发现这个没有单调性,所以就放弃了
换一个角度, 对每个人的获得量和当前剩余的钱数进行维护
对于每个货物,二分得到买得起它的子树,打钱数减少和答案增加的标记
对于权值减少后的重复,也就是 的 暴力插入平衡树里面,剩下的因为肯定还是权值大的部分,直接合并
每次插入会导致 减少一半,所以复杂度是合法的
这个标记下方要注意,尤其是最后输出答案的时候要遍历全树下放标记
【Hdu6087】Rikka with Sequence
维护原始的平衡树来对付 操作,每次拆出来对应的区间合并就行
对于 操作,考虑 的时候这个区间是会被不断复制的
那么把区间分裂出来,然后倍增出来每段的树,最后统一合并区间即可
这里还有一个 是定期重构,具体而言: if(tot<M-N/3) rebuild();
cdq 分治
Luogu4655
一万年没写过斜率优化了,所以重学了斜率优化
式子是 的,如下:
如果 同时
那么 的决策比 优
但是 不保证满足任何条件,所以我们并不知道这要维护个啥凸包
所以 分治来解决动态凸包的离线维护:
按照 分治优化 的原理,先处理左侧的 区间内左边对右边的贡献,最后处理右边的答案
对于当前分治区间 ,先按照 排序,处理左边的答案,回溯之后把左边的凸包建出来,这样满足转移都是有效的
然后把右边的点按照 排序进行转移即可
复杂度 或者用 就多个
具体实现的时候也可以先把所有点的 都扔到 上然后每次转移可以方便一点
Luogu4849
然后就写了个 套 的模板题……
由 的原理,考虑 掉若干维之后剩下的维中左对右的贡献
处理低维 的时候我们本质上是把左侧的 只转移给右侧的
那么先做一次 把 也同样操作一下,标记上是
所以 的才可以添加进入 同时 的才可以查询
再套上个 支持多维偏序即可
代码其实 ,想法确实有意思
Luogu6007
设 表示到 的最小步数
转移是 的,
既然是个 的题目,那么总该有点 的求最大值的样子
所以考虑转化成最多节省了多少步,则答案为
每次支持查询 的最大的 即可
稍微转化一点的
目前不会 的 的做法
虚树
HNOI2014 世界树
得到一个朴素的 ,设 表示 的归属,那么 可以得到
时间复杂度
但是这样虚树的数据范围就没用了,发现其实可以分割链的贡献
不难进行若干次 求出来每个虚树上的点的归属,设为
对于一条链 分如下的情况讨论
如果 那么直接找到 在 方向上的儿子 ,贡献是
二分端点, 的贡献并不难得出来
虚树上的点不在虚树上的子树的贡献,显然应该贡献给
时间复杂度
HEOI2014 大工程
建虚树,然后 考虑每个虚树上的链的贡献即可
注意:每个链的经过次数是
点分治
分岔路口
显然先跳然后走会比较优秀,那么这个做法对两点的距离没有要求,而且答案一样
所以计算一下这个分界然后判断即可,写出在对于一个范围:
表示在范围内的点的个数, 表示这些点的距离和,这部分可以使用点分治/树
函数和 都是连续的,交点必然只有一个,所以可以使用二分求交点
实现的时候每次让 对二分得到的期望取 保证正确性
luogu4115
本来想套 捉迷藏的线段树维护直径的做法,但是交了几次发现不行
其实也就是因为那个题的边权都是正的,这题从下往上传递信息的时候会挂掉
那么还是去想点分治
每个点存到点分树夫亲的距离 和 所有点分树儿子的最大值
具体维护时,用第一个堆来维护第二个堆(这里看了题解)
当然需要支持可删除堆来代替 ,那么我又复习了如何写可删除堆
想了半天才懂,懂了就好说了
CF990G
大力点分治,每次直接 合并子树信息即可
不太清楚为啥能过,但是过掉了
看题解说 有收敛性?
Luogu2664
如果当前点 的颜色是从根到之的第一次出现的,那么它对于根的其它子树的答案有 的贡献
那么我们现在仅考虑如何求得跨过 的答案
考虑记在当前分治重心的总权值和为 ,那么其对于 的贡献要减掉 子树里面的点的贡献
接着考虑在 的路径上的点,设个数为 不难得到贡献应该是其它子树里面的和:
大体思路并不复杂,魔鬼永远在细节:分治重心的处理和子树内部颜色的重复
需要想清楚,想清楚了并不复杂
归总,写很多个 就行了
注意!!点分治找重心的时候记得清空
Codeforces150E Freezing with Style
首先把中位数都离散化下来,然后点分治的过程中进行二分
以上都是从 中套出来的 套路
显然是考虑对于每个分治重心维护跨过其的最大的两个链进行合并
中间套个单调队列维护两个信息就行了
貌似单调队列写了一万年,为啥都快省选了单调队列这种东西还要调……
Luogu3714
点分治,接着考虑如何合并两个子树的信息
按照上个题的思路,两个不同颜色的合并需要减掉对应的代价
具体而言,对于每个扫出来的子树,合并长度为 的路径信息就查 最大值
所以搞俩线段树,颜色不一样的时候线段树合并就好了
动态 DP
如何求带修改的最大独立集?
把转移分成两个,即 表示(不)选择当前点的答案
同时 (不)考虑重儿子当前点的答案
这东西可以写成一个矩阵乘法的形式
那么每次被更改的 数组构成一条链,对矩阵开线段树维护即可
卡常方式貌似是用 或者循环展开
有效的是每个重链开线段树来降低 的复杂度
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律