专栏文章
题解:P13012 【MX-X13-T7】「KDOI-12」No one can be anything without comparison.
P13012题解参与者 2已保存评论 1
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 1 条
- 当前快照
- 1 份
- 快照标识符
- @mioxsiy1
- 此快照首次捕获于
- 2025/12/03 02:53 3 个月前
- 此快照最后确认于
- 2025/12/03 02:53 3 个月前
这个 12s, 2GB 看起来就让人很有做的欲望。NOI 前几天谁还做正经题啊。
不需要树分块,好像比正解简单一点?而且只需要保留一棵树的形态,剩下的的限制只要是区间包含单点就可以做。但是复杂度和正解相同,可能本质相同吧。(upd:确实本质相同,我的做法是将祖先关系描述成一个点子树的一段区间,另一个做法是将祖先关系描述成一个点到根的链,都是转化成了某种线性的结构)
本来以为是巨大数据结构的,写完发现超级好写,失策了。
思路
先转化一下祖先的关系。放在 dfs 序上,设在第 棵树上每个点的新编号是 ,每个点包含的编号区间是 (有 )。那么一个有序对 合法等价于 。
首先考虑 左右的复杂度怎么做。这是一个环的限制,所以无论如何是需要枚举一个点的。枚举 。设 表示走到第 棵树的第 个点的方案数。对于一个状态可以转移到一个区间,所以差分并还原即可。注意,转移后的下标是新编号,需要转化为原编号。
统计答案时,最后的限制是 在第 棵树上是 的祖先。所以考虑解决这个限制。这里有两种思路,一种是从上到下 dfs,在 处修改, 处查询,再撤销 的贡献。另一种是 dsu on tree, 处修改, 处查询。先保留这两种思路,之后再看哪种更合适。
考虑 怎么做。对于第一种思路,在 处查询时 是一段区间,贡献是 对应的区间包含了多少个修改的 。考虑分块,那么散块就是单点修改区间查询(可以使用 - 的分块平衡)。整块有很多区间,但值域只有 ,所以可以压缩信息。具体地,预处理,使用之前提到的做法求出每一个块对于每个 的答案。对于每个 的修改更新每个块的答案即可。对于第二种思路,思路其实是一样的。将 的贡献分为整块和散块两部分,对于整块打上加一的 tag,散块区间加。查询 时遍历每个块就可以算出整块的贡献,对于散块的贡献单点查询即可。
可以发现这两种思路本质是一样的。都是将贡献拆成整块和散块两部分,对于 和 在某一个整块上都有特定的贡献( 是 , 是预处理的值),答案是将两者相乘。而散块就是将单点和区间的修改和查询的对应关系交换了,它们都是好做的。而第二种思路多一个 ,所以接下来只考虑第一种思路。
可以发现整块的贡献可以扩展到 ,因为值域是 ,所以随时都在压缩信息,信息量不会随着树的个数而指数增加。而散块终究是不好做的。于是考虑将块长开很小,对于散块暴力枚举并递归到下一棵树的子问题。最开始我以为这样做的复杂度是 的,于是可以设 ,就做完了。写完才发现递归到下一棵树的时候还需要枚举整块,在最后一棵树的时候会出现 ,非常不牛。
能改进吗?考虑将第二棵树的块长开大一点,第三棵树的块长再开大一点,这样没准能平衡。设 分别为三棵树的块长,那么运算次数是 。取 ,从后到前依次取等,可以得到 。这样就得到了 的优秀复杂度(而且还没算预处理的 )。
我还真写了这个思路,甚至只跑了 40 多秒。其实确实合理, 估计就这么快,这个思路主要是为了压缩空间。
当我准备卡常的时候我突然看到了一段区间求和的代码。在递归的过程中完全不需要遍历整块!只需要在修改的时候动态维护前缀和即可。那为什么最初没发现呢?因为 的时候块的个数与块长都是 ,就没有区分它们,但是现在块的个数对复杂度产生影响了。所以要跳出思维定式。但是一步一步推过来想发现这一点对于我来说可能还挺难的。
于是这样的复杂度就是 了。取 可以得到 的复杂度。我取的是 ,最后卡着时限过的。想要更快可能可以将整块的询问离线,这样可以优化空间访问。
相关推荐
评论
共 1 条评论,欢迎与作者交流。
正在加载评论...