2019年7月25日木曜日

UTPC 2013 F - 魔法の糸

UTPC 2013 F - 魔法の糸

解説を見てACしたのだが、実装でつまづいた……というか、計算量がよくわかっていなかったのでメモ。

頂点ppを含む連結成分V(p)V(p)と頂点qqを含む連結成分V(q)V(q)を併合するとき、V(p)V(p)V(q)V(q)の間の辺をどう集めるかが問題になるが、重みを隣接行列にでも記録しておいて、単にV(p)V(p)の頂点とV(q)V(q)の頂点のペアを総当たりすればよい。こうすると、この部分の計算量がQQ回の更新でO(N2Q){\mathcal O}(N^2Q)になってしまいそうな気がしていたのだが、よく見ると1つの頂点ペア{v,w}\{v, w\}につき高々1回しか処理されていないので、O(N2+Q){\mathcal O}(N^2+Q)で済んでいる。

全体の計算量について。Kruskal法の前に辺の長さでソートする部分がボトルネックになる。頂点pp, qqを結ぶii個目のクエリに対して、V(p),V(q)V(p), V(q)の間の辺がdid_i本あったとすると、上で述べたようにd1+...+dQMd_1+ ... + d_Q \le Mである。また、以前のクエリでV(p)V(p)の最小全域木を作ろうとした時に選んだ辺は高々V(p)|V(p)|であり、V(q)V(q)についても同様にV(q)|V(q)|である。V(p)+V(q)N|V(p)|+|V(q)| \le Nだから、ii個目のクエリで扱うべき辺の数は高々N+diN+d_i本となる。したがって、QQ回のソートの計算量は

O(i=1Q(N+di)log(N+di))=O(i=1Q(N+di)logN)=O(i=1QNlogN+i=1QdilogN)O(QNlogN+MlogN)O((N2+M)logN).\begin{aligned} & {\mathcal O} \bigl (\sum_{i=1}^Q(N+d_i)\log(N+d_i) \bigr) \\ = & \: {\mathcal O} \bigl (\sum_{i=1}^Q(N+d_i)\log N \bigr) \\ = & \: {\mathcal O} \bigl (\sum_{i=1}^Q N \log N + \sum_{i=1}^Q d_i \log N\bigr) \\ \subseteq & \: {\mathcal O} \bigl (QN \log N + M \log N\bigr) \\ \subseteq & \: {\mathcal O} \bigl ((N^2 + M) \log N\bigr). \end{aligned}

ソートの部分はバケットソートでも通って計算量はO(N2+M+Qmaxwi){\mathcal O}(N^2+M+Q\max w_i)となる……けど、別に速くはならない。