2024.4 做题记录
2024.4 做题记录
[NOIP2018 提高组] 旅行
看到题目中要求
① 当
此时数据为一颗树。
我们贪心的想:起始点为
复杂度
② 当
此时数据为一颗基环树。
我们先找出环,然后考虑枚举这个环上的一条边,将这条边删去后就与情况 ① 相同。而此时枚举完所有边,将答案取最小即可。
复杂度
我们考虑,本题的关键在于:当走到一个环上的时候,从哪一个点
考虑什么时候回溯。首先想到的是当走下一个节点不如回溯之后走到的第一个节点,那么必然要回溯。但是这并不一定。如果这个节点不是父亲节点所有出点中最大的,那么回溯之后要走一个比当前点还要大的点,显然更劣。
因此,回溯的条件是:当这个节点是父亲节点所有出点中最大的,并且还要大于回溯后走到的第一个节点。
具体实现可以记录回溯后走到的第一个节点,记录是否回溯来实现。
复杂度
[IOI2008] Island
首先,观察题目以及样例,发现有些玄妙。我们先不管船,单独看桥会发现一个联通块内的答案就是树的直径。然后来看船,显然对于任意一个联通块内的节点都不能使用船,因此船只能用于两个联通块之间的交通,并且每个联通块只能走一遍。
再次观察题目会发现边数等于点数,即整个图是基环树森林,于是最后这道题就可以转化为:
给出几颗基环树,求出其直径之和。
其实这是一道板子,不过可以写一下。
考虑环形 dp 处理方式,首先对于一颗基环树,看做一个环上挂着一些树。对于子树内求出最长链的长度,然后作为环上这个点的点权;现在我门有点权
此时这个式子要在环上 dp,这时考虑朴素的处理方式——断环为链。此时在设
其中
发现取
最后取 dp 最大值,然后累加答案即可。
剩下的还要注意很多细节:
- 基环树的直径可能就是一颗子树的直径,因此在 dp 过程中还可以记录次长链直接求出子树直径。
- 边权有
,因此要开long long
。 - 单调队列优化 dp 的时候注意赋初始值。
[POI2012] RAN-Rendezvous
首先这是一颗基环外向树森林,因此分类讨论:
- 当两个点不在同一颗基环外向树时,显然没有答案,输出
-1 -1
即可。 - 当两个点在环上同一个点的子树内,答案就是两者的 LCA,随便用一种方式维护即可。
- 当两个点在环上不同点的子树内,两者都先走到各自在环上的节点。接下来由于是在环上,所以无论从哪一个走到哪一个都有可能,因此求出两个答案后取最优的即可。
[hdu6305] RMQ Similar Sequence
首先看到要求期望,那我们先将他拆开。即一个数列之和的期望以及数列符合 RMQ 相似的概率。二者乘积即为答案。
先看第一部分,这一部分较为简单。对于每一个数,在
接下来是 RMQ 相似的概率。这一步需要想到笛卡尔树,我们建立
两者相乘可得答案为
[COCI2008-2009#4] PERIODNI
这道题与笛卡尔树的经典板题 最大子矩形 有些相似,但是又有区别。
首先建立出
接下来我们直接在笛卡尔树上讨论问题。根据计算得到,一个节点对应的矩形的长就是
那么我们又会发现,子树中所有节点对应的矩形都在该节点对应矩形的上方。因此当子树中其他节点对应的矩形中放了
然后考虑怎样计算答案,需要亿点树形 dp。设
这个式子爆算是
显然后一部分可以
[hdu6854] Kcats
首先看到这个单调栈就可以想到笛卡尔树。那么我们先以
性质:对于
, 就是所有节点中深度小于 号点的点中,下标小于 的个数加一。 证明:由于
满足小根堆性质,因此只要深度小于 ,就代表权值小于 ,也就意味着在单调栈中会在 的底下。同时还要满足这些数出现在 以前,因此下标也要小于 。最后加上的一个 就是 本身。
那么有了这条性质可以干什么呢?
我们知道,笛卡尔树上节点子树对应一段区间。而下标是具有二叉搜索树性质的,因此左子树答案就是该节点答案,右子树答案是该节点答案加一。而根节点不确定,因此要枚举根节点,将区间砍成两端。
看到这些会想到什么?区间 dp。设
最后的组合数表示选出左子树的方案数。
但是还有可能
初始化为
[poj2482] 窗内的星星
首先考虑将一颗星星转化为一个矩阵。我们考虑右上角的范围,会初步发现当右上角所在的
问题是我们不能在构建矩形的时候带上小于号。考虑转化。如果矩形右上角所在的点
我们不需要求出矩形个数,因此这样做是正确的。
那么现在我们就按照这个构建矩形,每个矩形的上下边的权值就是
此时维护的是区间最大值以及区间修改,使用懒标记即可。
但是我们又会发现一个问题:按传统扫描线的存线段的方式无法使用,因为此时求的是点的信息。因此我们将线段树改为存储每一个点的值即可。
[USACO12OPEN] Balanced Cow Subsets G
首先看到
我们考虑一个数的状态,有三种:放入左边集合,放入右边集合,不放入集合。
总共有三种情况,也就是复杂度
考虑折半搜索。这样我们记录下每次集合中的状态。设第一次搜索放入左边集合的数字之和为
但是如果简单这样枚举,会发现有重复情况。因为一个数放入左右集合都是放入了集合,因此我们还需要去重。考虑状压,每次记录二进制串,然后用离散化去重即可。
[SDOI2015] 寻宝游戏
其实和虚树关系不大,只运用到了一点思想。
首先考虑所有关键点走一遍的边权之和,由于原图是一棵树,因此每条边都会被走两边。同时,我们可以得到如下式子:
当我们将
接下来考虑计算答案,显然不能每次统计,需要求出一个点的修改对于答案的贡献。
先以加点为例,显然我们需要找到在原式中和他连接的两个点。设这个点为
删去点同理,改变符号即可。
现在考虑维护这个东西,我们需要查询 DFS 序的前驱、后继,还要支持动态插入和删除一个数。这不就是平衡树板题吗,用 FHQ 维护即可。
当然我们也可以用 STL 自带的 set
简单处理。
[ZJOI2019] 语言
首先将答案转化为每个点的贡献,也就是要求出这个点可以到达多少个点。
设这个答案为
不难发现对于一个点
因此其实
此时我们需要看一个小小的经典结论:
引理:树上
个关键点之间形成的最小联通子树的大小为 (按 DFS 序排序后)。 我们考虑将
按照 DFS 序排序后一一加入联通子树。当我们加入第 个点时,由于 DFS 是升序的,所以此时 就是离 最近的点,算出两者间距离即可。最后还要减去所有点的 lca 的深度。
于是我们就可以暴力计算出
我们考虑对于每个点记录一个桶,桶的下标是 DFS 序。当桶的元素为
然后接下来我们考虑优化,对于
那么由于我们进行了树上差分,就必须要合并。那么要合并的东西是一个数组,显然直接合并
这时会想到什么?对于每个点的数组单点修改,然后进行合并。这不就是线段树合并板题吗!
因此对于每一个点,维护一颗线段树表示 DFS 序的桶,在线段树上操作一下即可。
注意这样算没有考虑大小关系,因此要除以二。
时间复杂度
[HNOI2014] 世界树
首先虚树的操作是显然的,问题就在于建出虚树后怎么做。这里我们采用
首先我们需要求出每个点所对应的议事处,然后计算这个点对该议事处的贡献即可。
我们接下来需要分类讨论:
一、对于在虚树上的点:
可以通过两次 DFS 求出这个点的议事处,即 up and down。
具体的,第一次 DFS 按照路径长度求出子树内到自己最近的议事处,第二次 DFS 求出子树外到自己最近的议事处,两者取较小值即可。不再赘述。
二、对于不在虚树上的点:

图中蓝色点为关键点,绿色边表示虚树边。
这一部分才是我们讨论的重点,再次分类讨论:
① 对于是虚树上的点的子树中的点(即黄色点)
那么此时我们只需要计算出这个点除掉在虚树上的子树的子树大小,将这个加到对应议事处的答案上即可。这个可以运用第三个 DFS 解决。
有一个小问题在于:如何除掉这个点在虚树上的子树?
假如现在遍历到点
,很显然我们要除掉 的子树大小。问题是虚树上并没有 的儿子信息。 其实这个问题也很简单:发现
在虚树上的儿子为 ,那么 在 方向上的儿子其实就是 的 级祖先。 利用倍增求解即可(这就意味着树剖性价比不高了)
② 对于不是虚树上的点的子树中的点(即绿色点)
此时我们就是要处理虚树上两点
还需要分类讨论:
显然整个中间这一部分都是
此时我们扩大一下视野,就是要把
这里我们利用二分简单查找一下即可。
最后我们输出所有议事处的答案即可。然后由于有多测,所以我们还需要用第五个 DFS 清空所有数组。
(其实算上倍增 LCA 的一个 DFS 总共有
[BJOI2017] 树的难题
首先容易想到点分治,问题在于如何统计经过点
首先我们可以维护每条根链上的权值以及长度。先考虑更简单的情况,即不考虑颜色段的情况。
这时求法是显然的,考虑维护一颗线段树,下标为链长度,然后对于当前根链在线段树上的特定区间内直接查询即可。
接下来考虑维护颜色段,我们发现,对于末尾颜色相同的两条根链,需要在求和后减去该颜色对应的权值;而颜色不同则不需要。
我们考虑对于每一种颜色维护一颗线段树,但是这样复杂度过高。
考虑我们并不需要知道每种颜色的具体信息,只需要知道所有与他不同的颜色即可。因此实际只需要维护两颗线段树:颜色与当前根链相同的,颜色与当前根链不同的。
然而我们不能在颜色改变的时候简单维护这两颗线段树,考虑将颜色排序,在同一颜色之内只需要修改第二颗线段树。当颜色发生改变时,只需要将第二颗线段树的信息合并到第一颗线段树上,然后清空第二颗线段树即可。
考虑到需要实现清空以及合并操作,采用动态开点线段树更为简单。复杂度
[BZOJ3697] 采药人的路径
首先还是考虑点分治,但是我们发现合法的路径条数并不好求。
不好求的原因在于我们需要一个休息点,这个并不能够简单求解。
我们先转化题意,将
我们想到点分治的本质是不断将当前子树信息与之前的子树信息合并,考虑这样的 dp 思想:我们设
在这样的 dp 思想下,我们会发现一些性质,例如对于下图:
假设
此时我们就知道。在
同理,当我们从
那么我们便可以总结如下:
- 如果当前节点对应的路径之和
是第一次出现的话,就需要找到前面路径之和为 且不是第一次出现 的点。根据 dp 状态,可知答案就是 。 - 如果当前节点对应的路径之和
不是第一次出现的话,我们只需要找到路径之和为 的即可,答案为 。
但是这样我们还没有讨论完全,当
- 如果当前节点对应的路径之和
是第一次出现的话,我们只需要找到前面路径之和为 的即可,答案为 。 - 如果当前节点对应的路径之和
不是第一次出现的话,它肯定可以和前面路径之和为 的构成完整合法路径,但是同时这条链本身也就是一个完整合法路径,因此此时答案为 。
我们在点分治的时候维护 dp 数组即可。
[HNOI2015] 开店
首先发现题目求的是
此时我们在每个点
:下标为 表示 :下标为 表示 :下标为 表示
那么答案式子就可以抽象转化为
我们试图使用线段树维护这些信息,然而我们发现
我们发现此题并没有修改操作,因此使用线段树大可不必。考虑 vector,用二元组存储
我们将
但是这道题有一些卡常数。我们发现
[ZJOI2015] 幻想乡战略游戏
首先从暴力入手。可以考虑枚举每一个点到树上其他点的距离,这样做是
我们考虑这与树上路径有关,并且还带有修改操作,因此想到点分树。我们可以用点分树维护每一个点到树上其他点的距离之和,时间复杂度就是
我们考虑原树上的一些性质。假如我们当前以点
我们考虑将
考虑这样一件事:假设有两个点
这说明什么呢?很简单,对于一个节点
此时我们就可以考虑这样的做法:枚举每个点的儿子,如果儿子更优则进入儿子,反之计算自己的答案。计算答案就使用点分树。
我们考虑这样做的复杂度,显然这与树高有关,设树高为
如果树被卡成一条链,那么显然
但是在点分树上没有原树的儿子信息,这时我们对于每个节点记录一个
这样我们的复杂度就是
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律