并查集——启发式合并,路径压缩
一直没想过自己写的并查集的复杂度= =。。。看那一行代码还挺窃喜——贴一下正版的启发式合并,这样复杂度就真正到了反阿克曼函数那什么balabala
一个优化是:把小的树合并到大树中,这样会让深度不太大。这个优化称为启发式合并。
一个优化是把沿途上所有结点的父亲改成根。这一步是顺便的,不增加时间复杂度,却使得今后的操作比较快。这个优化称为路径压缩
用 p[i] 表示 i 的父亲,而 rank[i] 表示 i 的秩,并用秩来代替深度做刚才提到的启发式合并。
void makeset ( int x ){ rank [ x ] = 0; p[x] = x; } int findset ( int x ) { int px = x , i ; while ( px != p [ px ]) px = p [ px ]; // find root while ( x != px ) // path compression { i = p [ x ]; p [ x ] = px ; x = i; } return px ; } void unionset ( int x , int y ) { x = findset ( x ); y = findset ( y ); if ( rank [ x ] > rank [ y ]) p [ y ] = x ; else{ p[x ] = y; if ( rank [ x ] == rank [ y ]) rank [ y ]++; } }
Sometimes it s the very people who no one imagines anything of. who do the things that no one can imagine.