一些数据结构题

题目来源是我在 2025 年参加的所有集训,会在题目后面注明是谁讲的。难度说明:

\(1\):无论睡没睡醒,都必须要迅速场切的题。

\(2\):无论睡没睡醒,都必须要场切的题。

\(3\):正式比赛需要场切的题。

\(4\):如果明年我能去 NOI,且 NOI 上放了这道题,且我有充裕时间做这道题,必须场切的题。

\(5\):到退役也不太可能场切的题。

CF2111G qazswedx 2

三个维度,没有修改。扫描线消去值域维后就是两个维度的静态问题,同时形式是一个矩形,非常好做了。矩形加,单点和,修改都在询问前面,扫描线,可持久化一下即可。

CF2096F qazswedx 2

充要是 \(1\) 不被 \(0\) 包含。注意到可以双指针。简化问题,我们实际上只需要判断一个合法到不合法的过程,而无需判断不合法到合法的过程。合法到不合法的过程无非是加入 \(0\) 操作和 \(1\) 操作。

对于加入 \(0\) 操作,我们考虑这次操作后包含该次操作的最长 \(0\) 区间,然后需要查询是否有 \(1\) 操作被包含在了这段区间中。维护 \(mx_i\) 代表 \(i\) 作为 \(1\) 操作右端点时最大的左端点。

对于加入 \(1\) 操作,维护 \(c_i\) 代表这个位置被 \(0\) 操作覆盖了多少次即可。

\(c_i\) 的维护是简单的。\(mx_i\) 的维护只需套一个 multiset 维护即可。均摊以后是单 \(\log\)

CF2129E qazswedx 3

首先这种题看上去就很不可以 polylog,信息经过任意预处理后合并复杂度仍然不会低于某个值。

当每个点贡献不相同的时候,通过带权分块来平衡莫队中每个点的贡献。

P8518 zhuyifan 3

考虑画成折线图的形式,此时若只有上界或者只有下界都是好做的。但是上下界都有,看上去很难维护。做一些观察,注意到当一段的极差大于等于 \(c\) 时,最后一个取到的最值会碰壁。放在后缀上考虑这个事情,找到最短的一段后缀使得极差 \(\geq c\)。则最后一个取到的最值之后都不会再碰壁。找到后缀只需换维扫描线。

考虑为什么使用换维扫描线。我们显然需要对每个位置维护时间轴,扫描时间维后操作在序列维上可以差分,大概也可以维护。注意到差分以后仍需要维护多棵线段树,很不厉害。

P9530 zhuyifan 4

\(O(\log n\log A)\) check 一条鱼能否存活是简单的,然后发现很难扩展了。第一反应应该去思考这题是否是 polylog 的,带修莫队这种东西看上去就很不能过,因此最终做法不可避免需要对两段区间信息进行合并。抛开时间复杂度,考虑需要记录什么。如果一条鱼无法吃到左端点或者右端点,那么这条鱼就没有用了;尝试记录能吃到左右两端点鱼的数量。

这样还是无法进行信息合并,因为即使用“全能吃到左端点”这种特点去记录鱼,所有满足条件的鱼还是没有什么很好的统一形式,必须记录所有鱼的信息。或许这样的鱼不会很多?如果用三元组 \((id,l,r)\) 记录一条鱼,那么可以轻松将信息卡到很大的级别。考虑实际上 \(id\) 是不重要的,记录二元组 \([l,r]\) 及取到这个二元组的数量即可。这样的二元组不会很多:考虑对于 \(r_1<r_2\)\([l,r_2]\) 的重量必然至少为 \([l,r_1]\) 重量的两倍,因此二元组只有 \(O(\log A)\) 个。

考虑信息合并,合并之后包含左端点的二元组无非三类:

  • 左区间内包含左端点的二元组向右扩展。
  • 左区间内包含右端点的进行扩展。
  • 右区间内包含左端点的进行扩展。

第一类十分好做。考虑第二类,此类贡献存在性质,处理之后第二类贡献带来的 \([l,r]\) 只有一个,较容易说明。求出是哪个只需二分即可,考虑统计数量。若将所有第二类中的区间按照包含关系排序,那么只需求出最小的满足能扩展到答案区间即可统计数量。直接对其二分可以做到 \(O(\log n\log A\log\log A)\)。任取某个区间 \([l,R_0]\),那么二分可能将其扩展为 \([x,y]\),我们说明,\([R_0+1,y]\) 是右侧区间内某个包含左端点的二元组,证明不妨考虑最大的 \(z\) 使得 \([R_0+1,z]\) 是右侧区间某个二元组且 \(z<y\)(这显然存在)。考虑若 \(z+1\) 的重量超过 \([R_0+1,z]\) 的重量,那么会有一个 \(z'\) 满足 \([R_0+1,z']\) 是一个被记录的二元组且 \(z'>y\),通过模拟 \(z+1\) 吃鱼的过程不难发现 \([l,R_0]\) 可以扩展到 \([R_0+1,z']\);若 \(z+1\) 的重量不超过 \([R_0+1,z]\) 的重量,可以同样分析。

于是对其双指针可以做到 \(O(\log A)\) 时间内求出第二类贡献。整个过程并不是很 trivial,指针移动顺序是固定的,但是信息维护需要用到后移动到的点,注意到我们不关心每个左端点的信息到底是多少,只关心某个右端点上信息的和,以及这个右端点是极大的。于是我们暴力往左右两边移动,同时优先往右边移动,就能得到右端点取到极大时的信息。

第三类贡献大同小异。时间复杂度 \(O(n\log n\log A)\)。为了少维护一点信息,可以用 \(O(\sqrt n)-O(1)\) 的单点加区间查平衡 \(O(n\sqrt n+n\log n\log A)\)

代码

2025.8.21 pyyz 模拟赛 t1 qazswedx 5

直接做很难刻画操作。考虑找到一种方式刻画操作,一个操作必然可以刻画为 \(xxxx?????xxxxx\) 的形式,其中低 \(k\) 位被 \(t\) 确定,高位被 \((l,r)\) 确定,操作的位置就是中间问号任填的结果。

考虑修改对查询的贡献,需要满足非 \(?\) 位置相等,设相交的问号个数为 \(y\),那么贡献就是 \(2^y\)。对于查询枚举相交的问号部分,剩下部分分类讨论后可以哈希表维护。

2025.8.16 pyyz 模拟赛 t3 aaa12321 4

暴力告诉我们,我们只需关注 \(O(\sqrt n)\) 种环长,只需要把每种环长最靠前出现的那个环拿出来即可。如果能快速维护所有环,那么就可以直接做了。考虑操作无非是断开环和合并环,用平衡树维护每个环,将环移位、合并环、分裂环都可以用 \(O(1)\) 次 split 和 merge 进行维护。时间复杂度 \(O(n\sqrt n\log n)\)

这个做法几乎没有利用到查询的性质。考虑查询时我们会先判断 \(|x-y|\) 是否被 \(d\) 整除,如果不整除那么直接判断环上两个位置的大小关系求出答案。于是,若我们维护前缀环长的 lcm,可以快速找到不合法的环,依然用平衡树维护环,线段树维护 lcm,按照线段树维护 gcd 的方法分析,时间复杂度单 \(\log\)

P7470 dXqwq 4

见我别的博客。

炼石计划 day6t4 最小生成树 4

感觉是,套路题,没做出来,我的问题。

将贡献放到 LCA 处统计,分成三种。

轻子树对轻子树,先把所有轻子树信息加入 trie,再将需要遍历的那棵从 trie 减去,遍历一遍。每个点只会被加入删除 \(O(\log)\) 次。

轻子树对重子树,遍历过程中将所有轻子树信息加入 trie,遍历,结束以后再撤销。

重子树对轻子树,和上面类似。

贡献对看似平方级别,实际上给出一堆串我们可以 \(O(\log)\) 算贡献。所以就考虑怎么把一堆贡献放到一起就行了。

炼石计划 day7t4 死神永生 5

出的不好,太强行了。但是如果 std 是 Southern_Dynasty 那种做法会好很多,只有前半部分比较强行。

直接忽略过于强行的那部分,考虑子问题,修改一条边的边权,查询直径端点。合并两棵树后的直径一定是原来两棵树的直径端点中选两个,虚树也是如此,线段树维护区间虚树的直径端点即可。

线段树分治做法基于这个题,没法推广。

P7124 stcm 4

怎么变成随缘更新了,就这样吧,太摆了。

正常人应该最先想到 dsu on tree 之类的东西,但完全做不了啊!直觉告诉我们需要乱平衡一下。做重儿子是很简单的,暴力加入所有轻儿子,这部分次数是 \(O(n\log n)\)

但轻儿子十分困难,换个思路,这个题并没有要求操作一必须加入相邻节点。所以依次处理每条重链,上面挂了若干个轻子树,显然轻子树不会有相互包含的关系,所以找到一个合适的顺序加入所有轻子树然后递归即可。建立哈夫曼树,总权值为 \(n\) 的哈夫曼树子树内不会超过 \(n\log n\)。所以在哈夫曼树上做即可。

另外一种做法更牛一点,对 dfs 序分治。处理跨过 mid 的子树时肯定不存在两个区间相交但不包含,所以按照偏序关系加点即可。

posted @ 2025-08-22 15:50  BYR_KKK  阅读(60)  评论(1)    收藏  举报