省选集训 day 1 数据结构杂题

link

A

比较套路的题目,第一次见还是有难度的。

关于 +1 的更改,事实上是找到二进制下极长的末尾 1 段并进位。

考虑使用 Trie 维护这个操作,相当于建立一颗从低位开始的 Trie,然后swap儿子并进入swap后的新左子树递归操作。

然后对于邻域的问题,一般考虑每个点单独维护其儿子,然后特别处理父亲。

B

发现对于把串插入 Trie 后每个 Trie 极大空子树独立,也就是相当于若干个 L 的空串的公平组合游戏。

那么答案就是这些空子树的 SG 值的 xor

考虑 SG(n) 的求法,这里表示树高为 n 的空 Trie 树,注意是树高,那么 n=0 指的是空树。

首先 SG(0)=0,因为此时已经必败。

其次考虑先手做一次可以达到一个什么样的局面:插入一个长为 h 的串,原树被分割为 nh,nh+1,nh+2n1 这样的子问题。

那么也就是 SG(n)=mex{j=nhn1SG(j)|0hn}

注意到 h=0 时取到零。

打表发现 SG(n)=lowbit(n)

C

考虑 xor mex 如何求解,显然可以考虑一个 dp,设 fi 为 Trie 上节点 i 的最大 xormex,有:

fx={flc+frclc\or rc is fulledmax(flc,frc)else

考虑到一个方法自底向上求解最优值,也就是对于 一颗满树 T,给其Trie上的兄弟子树的权值加上 |T|,然后找到权值最大的叶子即为答案。

通过这个方法,我们可以预处理每个 rO(n)(l,h),表示 qll 时,往上走 h 级的树满了,然后通过 Trie 打标记的方法(因为这些是统一的)在 O(2n·n·m) 回答询问。

这太差了,考虑到树 T 满上之后,事实上 T 内点不可能成为答案,并且我们只关心 T 的兄弟节点的最大值变化,所以可以只打一个标记在这里不用。

考虑 a 是排列的情况,那么每个子树只会被填满一次,那么可以扫描线,扫到 r 的时候对于若干对 (l,h) 我可以暴力访问其兄弟子树里所有节点更新答案并在这 n(l,h)l 划分的 O(n) 个区间将答案取 max

一共下来只会有 O(n·2n) 次操作,利用线段树求算答案也就是 O(n22n)

考虑到 a 不是排列的情况如何转化,我们的核心思想还是在于对于每个 r,求出若干对 (l,w) 表示 qll 时答案对 wmax

首先我们断言这样的 (l,r,w) 总数是 O(n·2n) 级别的。

还是考虑扫描线,每次考虑 (ar,r) 的影响,其中对于每个子树,使用一个 Trie 来维护这个子树的节点,我们称这样的trie为内trie,而原本的trie为外trie(也即有 O(2n) 个内 Trie,总结点数 O(n2n)),并且维护信息:当前点所在子树全满的最大 l 以及这个内 trie 的 dp 值。

首先将 (ar,r) 插入到外trie祖先的内trie里,我们可以得到这个 r 所对应的不超过 n 个的 (li,hi)

一个 (li,hi) 对答案的影响是什么呢?其实可以考虑其兄弟子树的最大值变化,因为我们实际上也只关心其兄弟子树的最大值。

对于每个子树维护一个集合 Pi 表示当前的内trie内节点,按照加入时间排序(也就是下标)。然后遍历 Pli 的节点逐个删除,包括在集合P删除以及在内trie上删除(这个点以后完全无用了,下次更新不会用到(已满)),并获得新的该子树的 dp 值作为这个时间段的答案

注意我们是加入 (ar,r) 时,也将 ar 的所有外 trie 上的祖先的 P 都加入它。

这样均摊下来所有的 P 的总插入量是 O(n·2n),总删除量不超过插入量。

但是注意到这个兄弟子树的答案还有一些情况,也就是从这个兄弟子树往上走祖先的时候,如果祖先的兄弟也满了,那么这个答案也是会更新的,但是这是增量

至于 ar 对应的单点,就只需要考虑祖先的兄弟满上的时刻。

需要在相应时间处理一遍。


注意到上面的复杂度有个瓶颈,就是往上走祖先找满了的祖先兄弟的增量。

这个卡满每次会有 O(n) 个,会导致 O(n2·2n) 个要求的 (l,r,w),因此我们需要想办法优化掉这些。

事实上我们发现所谓的 “祖先兄弟” 仅有 O(n) 个,我们虽然处理出与其相关的权值,但是我们每个 “祖先兄弟” 取其权值的最优值,那么也就只有 O(n·2n) 个。

同时为了处理 “兄弟子树” 的 “祖先兄弟”,我们先拿出所有祖先兄弟,然后将其按时间排序,并且用指针扫描(避免排序)处理贡献。

这样就可以做到严格的 O(n·2n) 了。


由此我们得到了 O(n·2n) 个二元组 (l,r,w) 表示扫描线到 r 时,qll 的答案对 wmax

由于答案具有单调性,我们可以在线段树上二分查找到更新的区间,那么我们需要的就是:支持区间覆盖,区间历史和求和。

线段树维护即可。

D

猜测结论是最大覆盖次数,因为这个是一个显然的下界。

事实上确实如此,只要我们能够证明这个下界可以达到。

考虑一个构造:每次将覆盖次数最大的点拿出,并拿出其中深度最小的点,这样的点一定会有其作为 lca 的路径,如果没有,那么它的父亲也是覆盖次数最大的点,与其深度最小矛盾。

使用全局平衡二叉树/树链剖分支持链修改,查全局最值即可。

E

预处理每个元素的极长有效区间 (l,i,r)

也就是询问:L,R 这个三元组有贡献需要有 L[l,i],R[i,r]

也就是 l[1,L],r[R,n],i[l,r],将这个三元组看作点,变为三位数点,上 KDT 即可。

F

非正解

利用 kdt 做 K 近邻搜索,注意这玩意的 估价函数设理论最优值,然后注意使用整体操作,也就是始终对 ans 进行操作(也就是并不是对于每个点找 k 个,而是维护一个答案集合,如果可能更新就去搜),使用可并堆即可。

posted @   spdarkle  阅读(8)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
历史上的今天:
2022-12-24 根号分治入门
点击右上角即可分享
微信分享提示