CF1588F 题解
题意
你有个长度为 \(n\) 的数组 \(a\) 和一个长度为 \(n\) 的排列 \(p\),对于每一个 \(i\) 有一有向边 \((i,p_i)\)。
有如下三种操作:
-
1 l r
询问 \(\sum_{i=l}^r a_i\)。 -
2 v x
将所有 \(v\) 能到达的节点所对应编号的值加 \(x\)。 -
3 x y
交换 \(p_x\) 与 \(p_y\)。
对于每一 \(1\) 操作输出结果。
\(1\le n,q\le 2\times10^5\)。
题解
发现操作 \(3\) 难以处理。先考虑没有 \(3\) 的情况。容易得出一个 \(O(n\sqrt n)\) 的算法:将操作分为 \(\sqrt n\) 块,对于每个操作 \(2\) 给对应环打上标记,对于操作 \(1\) 分为两部分算:同一块内的,考虑所有有标记的环,统计环上有几个点 \(\in[l,r]\),乘上标记;不同块的,在每块结束时 \(O(n)\) 统计一下即可。
再看有 \(3\) 的情况。此时环会合并或分裂。但当环的变化次数比较少时,环上很大一部分也是可以使用标记的。将所有 \(3\) 操作的 \(x,y\) 称为关键点,则关键点可以将所有环(参与合并或分裂的环)分为 \(O(\sqrt n)\) 条链。于是给链打标记,用类似上面的方法做。
分析一下复杂度。操作 \(2\) 的复杂度为 \(O(\sqrt n)\),操作 \(3\) 为 \(O(1)\),操作 \(1\) 为 \(O(\sqrt n\log n)\)。瓶颈在于二分。先将 \([l,r]\) 分为 \([1,l)\) 与 \([1,r]\),因为一条链上 \([1,r]\) 的个数不会随标记改变,于是可以预处理。这样就规避了二分。复杂度 \(O(n\sqrt n)\)。