【题解】Solution Set - NOIP2024集训Day8 并查集和可持久化并查集

【题解】Solution Set - NOIP2024集训Day8 并查集和可持久化并查集

https://www.becoder.com.cn/contest/5453

*注:如不加特殊说明,\(\alpha\) 均代表并查集的小常数,有 \(\alpha\le \log\)


「AGC002D」Stamp Rally

从小到大枚举边,加入就合并。\((x,y,z)\) 就是问第一次 \(x\) 所在集合大小 + \(y\) 所在集合大小 \(\ge z\) 的时候是多少。(如果 \(x,y\) 在同一个集合中只能算一次)。这样是 \(O(qm\alpha)\) 的。


考虑改成整体二分。整体时间复杂度为 \(O(q\log m\alpha)\)

只是比较难实现,每次新加边的时候要精细实现,不然很容易变成 \(O(qm\log m\alpha)\)

具体的,每次加边的时候记录所有的修改位置和之前的量(所以不能路径压缩),加完边,不清空,直接递归右边,然后再清空回去,递归左边。


或者,更直接一点我们直接把并查集可持久化,每次询问都直接二分,然后 \(O(\log q)\) 在可持久化并查集上面查。总共就是两只 \(\log\)


还有一个 kruskal 重构树的 \(O(q\log^2 n)\) 做法,有时间去复习一下。

kruskal 重构树本质上也是也就是在维护可持久化并查集的过程。—— yly


代码写的是整体二分。


「 CF1659E」AND-MEX Walk

观察样例可以发现,答案只有可能 \(0/1/2\)。(如果没有猫娘和揭的提醒,可能都想不到 /lb

考虑把每个 \(w_i\) 二进制拆分,然后按顺序放在表格的每一列。

我们发现如果要把每个 \(w_i\) 转化为 \(w_1\&\cdots\&w_i\) 其实就是把每一行的第一个 \(0\) 一直填充到行末。

考虑以下事实:

  1. 如果存在某一行都是 \(1\),那么答案就是 \(0\)。因为所有的值都大于 \(0\)
  2. 否则,我们考虑最后一行。
    1. 如果最后一行第一次出现 \(0\) 不是最后出现的或者就是最后一次出现,那么答案就肯定是 \(1\)。考虑最后两行,从左至右一定是:一段 \(3\),一段 \(2\),一段 \(0\)
    2. 否则,答案就应该是 \(2\)。考虑最后两行,从左至右一定是:一段 \(3\),一段 \(1\),一段 \(0\)

简述一下题解的证明:

考虑反证。如果最终答案 \(\ge 3\),那么在 \(\&\) 的前缀中一定存在 \(1/2\)。我们注意到 \(1=(01)_2,2=(10)_2\),无论这二者谁排在前面,都会使末两位中的某一位上面一直保持为 \(0\),从而此二者一定不能共存,与假设中 \(1/2\) 同时存在矛盾!

感觉还是挺妙的。根据结论来证,难猜的结论。


所以现在我们把一个计算题,转化成了判定题,因而要求的东西就明朗了。

首先判定答案为 \(0\) 的情况。

对于二进制的每一位,如果一条边权在该位上为 \(1\),就连边,然后用并查集维护联通块,查询的时候如果 \(u,v\) 在同一个联通块内,答案即为 \(0\)

然后判定 \(1\)

类似的,我们把末两位均为 \(1\) 的边连上,维护每个联通块。然后再把把末两位为 \((10)_2\) 的边连上,同样维护每个联通块。查询的时候,就看 \(u\) 在第一个图里面的联通块,和 \(v\) 在第二个图里面的的联通块是不是有交集。

和下面 「JOI Open 2016」销售基因链 又很类似,可以重标号转化为一个二维数点问题。


「JOI Open 2016」销售基因链

其实这道题想到 trie 就简单了。

考虑对所有串正反分别建一棵 trie。现在问题就转化为一个典问题:给定两棵子树求叶子节点的交集。

首先按照 dfs 序对其中的一棵树重编号,让子树内叶子节点变为连续的,然后另一棵子树线段树合并,最后求一下区间和就好了。


「Ynoi2010」Fusion tree/融合树

考虑给树上节点重编号。使得每个节点往下的那些节点都是连续的,于是一次修改就等价于线段树上的区间加,单点加,区间异或和。

现在难点在于如何,区间加,区间异或和。

每次区间加都是 1,这可能挺关键。而且区间一共只有 \(n\) 种,每种还互不相交。

不会了。😭


对于一棵 0-1 trie,我们可以对所有数字 \(+1\),然后维护异或和。

OI-Wiki

posted @ 2024-08-15 08:29  CloudWings  阅读(15)  评论(0编辑  收藏  举报