符号约定

下文固定一个正整数 nn,定义全集 U={1,2,,n}U=\{1,2,\dots,n\}

并查集用一个父亲函数 p:UUp:U\to U 表示,初始化 xU,p(x)=x\forall x\in U,p(x)=x

称一个父亲函数 pp 是合法的,当且仅当对任意 xUx\in U,不断应用 ppx, p(x), p(p(x)),x,\ p(x),\ p(p(x)),\dots 最终一定会到达某个点 rr,并且这个点满足 r=p(r)r=p(r),这个 rr 就叫做 xx 在父亲函数 pp 下的根,记为 rootp(x)\operatorname{root}_p(x)

一个集合划分 P\mathcal PUU 的若干个非空子集,它们两两不交,且并集为 UU

对合法的 pp,划分 Pp\mathcal P_p 定义为 \{ \[r\] \mid r\in U,r=p(r)\},其中 \[r\]=\{x\in U\mid p(x) = r\}

路径压缩

rootp(x)\operatorname{root}_p(x) 的函数 find(x)\operatorname{find}(x) 的操作过程如下:

  1. p(x)=xp(x)=x,返回 xx
  2. p(x)xp(x)\neq x,先递归求出 r=find(p(x))r=\operatorname{find}(p(x)),再令 p(x)rp(x)\gets r,并返回 rr

假设 xx 到根路径为 v1,v2,,vkv_1,v_2,\dots,v_k,其中 vkv_k 是根,那么本次操作就是 i, 1i<k, p(vi)vk\forall i,\ 1\le i<k,\ p(v_i)\gets v_k

下证设进行操作前父亲函数 pp 是合法的,那么进行一次操作之后父亲函数 pp' 也是合法的,并且 yU, rootp(y)=rootp(y)\forall y\in U,\ \operatorname{root}_{p'}(y)=\operatorname{root}_p(y)

证明

任取一个 yUy\in U

  • 如果从 yy 出发不断应用 pp 的过程中没有经过 v1,v2,,vk1v_1,v_2,\dots,v_{k-1},那么 yypp 下走过的路径与在 pp' 下相同,因此仍到达同一个根;
  • 否则设从 yy 出发在 pp 下第一次经过的被修改点是 viv_i,则在 pp' 下到达 viv_i 后下一步直接到达 vkv_k,此时 rootp(y)=rootp(y)=vk\operatorname{root}_{p'}(y)=\operatorname{root}_p(y)=v_k,并且 p(vk)=p(vk)=vkp(v_k)=p'(v_k)=v_k

集合合并

合并 x,yx,y 所在集合的函数 merge(x,y)\operatorname{merge}(x,y) 的操作过程如下:

  1. rx=find(x)r_x=\operatorname{find}(x)ry=find(y)r_y=\operatorname{find}(y)
  2. rx=ryr_x=r_y,不做更改,否则令 p(rx)p(r_x) 修改为 ryr_y

设执行了两次 find\operatorname{find} 之后,修改 p(rx)p(r_x)ryr_y 前的父亲函数是 pp,修改后的父亲函数是 pp',那么

  • 满足 rootp(u)=rx\operatorname{root}_p(u)=r_xuu 满足 rootp(u)=ry\operatorname{root}_{p'}(u)=r_y

  • 满足 rootp(u)=ry\operatorname{root}_p(u)=r_yuu 满足 rootp(u)=ry\operatorname{root}_{p'}(u)=r_y

  • 满足 rootp(u){rx,ry}\operatorname{root}_p(u)\notin\{r_x,r_y\}uu 满足 rootp(u)=rootp(u)\operatorname{root}_{p'}(u)=\operatorname{root}_p(u)

rx=ryr_x=r_y,则 p=pp'=p,显然合法;否则 rx,ryr_x,r_y 是两个不同的根,令 rxr_x 指向 ryr_y 后所有点都能找到一个根,所以 pp' 仍然是合法的。

DSU-NEXT

下面介绍一个常用的 trick,用来处理对一个固定的 nn,每次处理 lrl\sim r 中的所有点,但是每一个点只需要被处理一次,如将初始全 00 的序列区间修改为 11

定义带哨兵的全集 I={1,2,,n+1}I=\{1,2,\dots,n+1\},其中 n+1n+1 永远不会被删除,维护一个存活集合 SIS\subseteq I,初始为 S=IS=I

支持对这个集合 SS 进行如下两种操作:

  1. xS,xn+1x\in S,x\neq n+1,令 SS{x}S\gets S\setminus \{x\}
  2. SS 中查询 i\ge i 的最小的数,记为 N(i)N(i),这里不要求 iSi\in S,只要求 iIi\in I

因为 n+1Sn+1\in S 永远成立,所以 N(i)N(i) 总是良定的。

我们可以用并查集维护这个集合,具体地讲,初始时 xI,p(x)=x\forall x\in I,p(x)=x,那么:

  1. 删除操作实现起来即 p(x)rootp(x+1)p(x)\gets \operatorname{root}_p(x+1)
  2. 查询操作就是返回 rootp(i)\operatorname{root}_p(i)

我们来证明任意时刻都有 rootp(i)=N(i)\operatorname{root}_p(i)=N(i)

对删除次数进行归纳,没删除时显然成立,假设某次删除前集合为 SS,删除了 xx,分 x1,x+1x-1,x+1 分别是否存活四种情况画个图讨论即可。