Description
题目链接:BZOJ 1483
有 $n$ 个布丁摆成一行,每个布丁都有一个颜色 $a_i$,进行 $m$ 次操作。操作共有 $2$ 种:
1 x y
:将颜色为 $x$ 的布丁全部变成颜色 $y$ 的布丁。2
:询问当前一共有多少段颜色(例如颜色分别为 $1,2,2,1$ 的 $4$ 个布丁一共有 $3$ 段颜色)。
数据范围:$1\le n,m\le 10^5$,$0<a_i,x,y<10^6$
Solution
我们可以把每种颜色的布丁集合想象成是一个队列。那么就有若干个长度总和为 $n$ 的队列,每次操作需要合并 $x$ 和 $y$。如果我们暴力合并,那么合并一次复杂度最坏为 $O(n)$。
但是有个叫做启发式合并的东西!它的本质很简单:每次把短的合并到长的上面,那么合并一次的复杂度为 $O(|短的队列|)$。这样看上去貌似没有什么差别嘛 QAQ,接下来我们分析一下均摊复杂度。
考虑用贡献法来分析。我们令两个集合的分别为 $A$ 和 $B$,且 $|A|<|B|$,那么我们把 $A$ 暴力加入到 $B$ 中。那么 $A$ 中的元素所在的集合大小变成 $|A|+|B|$,也就是说至少变成了原来的两倍。所以每个元素至多被加入 $\log n$ 次,总的复杂度为 $O(n\log n)$。
对于这道题目,我们先求出原序列的答案,对于每一种颜色都用类似链表的数据结构串起来,并记录下尾节点。每次修改,都根据启发式合并的方法来暴力合并,然后处理一下此次合并对答案的影响(显然答案是不增的)。
但是如果我们把 $1$ 染成 $2$ 并且 $|S_1|>|S_2|$,那么我们应该把 $2$ 接到 $1$ 的后面。这样会有一个问题:本次修改后这个链的颜色是 $1$(颜色为 $2$ 的链被删除了),如果接下来修改颜色 $2$(显然这是合法的),会使得找不到颜色 $2$ 而只能找到颜色 $1$ 了。所以我们需要使用一个 $f$ 数组,表示当我们要寻找颜色 $x$ 时,实际上需要寻找颜色为 $f[x]$ 的链。如果遇到上面这种情况就要交换交换 $f[x]$ 和 $f[y]$。
时间复杂度:$O(n\log n)$
Code
1 |
|