0%

【题解】CF1907G - Lights

题目链接

https://codeforces.com/contest/1907/problem/G

题目大意

给定一个长度为 \(n\)\(01\) 串,有 \(n\) 个开关,按下第 \(i\) 个开关会反转位置 \(i\) 和位置 \(a_i\) 的状态(\(a_i \neq i\)),目标是让 \(01\) 串的状态变为全 \(0\)

报告无解,若有解,输出操作次数最少的方案。

数据范围

多组测试数据,保证

  • \(\sum n \le 2\times 10^{5}\)
  • \(1 \le a_i \le n, a_i \neq i\)

解题思路

注意到每个开关控制且仅控制两个位置的状态,所以我们可以把开关抽象成,把每个位置抽象成一个结点

我们发现总共有 \(n\) 个节点 \(n\) 条边,但是图不保证联通,所以建完图之后是一个基环树森林。

问题变为给定一个基环树森林,选择最小的边集,使得反转边集中所有边连接的两个结点的状态后,所有结点的状态都变为 \(0\)

其实只需要考虑一个基环树上怎么做。

首先可以注意到这颗基环树上状态为 \(1\) 的结点个数必须为偶数个,否则肯定无解。

其次可以注意到一条边只会被选择 \(0\) 次或者 \(1\) 次,选择 \(2\) 次跟 \(0\) 次的结果相同,所以我们可以将基环树上的环断掉,比一下选断掉的边和不选断掉的边哪个更优即可。

于是只需要考虑在一颗树上怎么做。

先假设只有两个状态为 \(1\) 的结点,显然最小的边集一定是两点简单路径上所有的边。

假设有四个呢?如果我们随便两两配对,发现路径可能有交集,这样是不优的,但是我们发现只要把路径交集去掉不选,剩下的不交的部分又构成两条新的路径,这样一定是最优的。

所以到此为止此题基本结束,我们只需要按照任意顺序给状态为 \(1\) 的结点配对,把所有配对的点对的路径上所有边的值加 \(1\) ,最后选择值为奇数的边即为最优方案。

用树上差分加上倍增求 lca 实现的话为 \(O(n\log n)\) ,瓶颈为倍增求 lca 。

参考代码

https://codeforces.com/contest/1907/submission/236342135