【题解】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\),那么答案就是 \(0\)。因为所有的值都大于 \(0\)。
- 否则,我们考虑最后一行。
- 如果最后一行第一次出现 \(0\) 不是最后出现的或者就是最后一次出现,那么答案就肯定是 \(1\)。考虑最后两行,从左至右一定是:一段 \(3\),一段 \(2\),一段 \(0\)。
- 否则,答案就应该是 \(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\),然后维护异或和。